diff options
author | Peter Ujfalusi <peter.ujfalusi@ti.com> | 2018-12-17 14:21:34 +0200 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2018-12-18 12:22:43 +0000 |
commit | f2055e145f2975a75dace8e386fad9364828cdb4 (patch) | |
tree | 447c549b6c72d4a8cedd34db1cb7b94691c21a16 /sound/soc/omap | |
parent | 0718f87b0df49570cdcb96179997bd372cac1742 (diff) | |
download | blackbird-op-linux-f2055e145f2975a75dace8e386fad9364828cdb4.tar.gz blackbird-op-linux-f2055e145f2975a75dace8e386fad9364828cdb4.zip |
ASoC: ti: Merge davinci and omap directories
Create new directory to contain all Texas Instruments specific DAI,
platform and machine drivers instead of scattering them under davinci and
omap directories.
There is already inter dependency between the two directories becasue of
McASP (on dra7x it is serviced by sDMA, not EDMA).
With the upcoming AM654 we will need to introduce new platform driver for
UDMA and it does not fit under davinci, nor under omap.
With the move I have restructured the Kconfig to be more usable in the era
of simple-sound-card:
CPU DAIs can be selected individually and they will select the platform
driver they can be served with.
To avoid breakage, I have moved over deprecated Kconfig options so
defconfig builds will work without regression.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
For sound/soc/{omap => ti}:
Tested-by: Jarkko Nikula <jarkko.nikula@bitmer.com>
Acked-by: Jarkko Nikula <jarkko.nikula@bitmer.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/omap')
-rw-r--r-- | sound/soc/omap/Kconfig | 120 | ||||
-rw-r--r-- | sound/soc/omap/Makefile | 30 | ||||
-rw-r--r-- | sound/soc/omap/ams-delta.c | 594 | ||||
-rw-r--r-- | sound/soc/omap/n810.c | 378 | ||||
-rw-r--r-- | sound/soc/omap/omap-abe-twl6040.c | 353 | ||||
-rw-r--r-- | sound/soc/omap/omap-dmic.c | 541 | ||||
-rw-r--r-- | sound/soc/omap/omap-dmic.h | 69 | ||||
-rw-r--r-- | sound/soc/omap/omap-hdmi-audio.c | 418 | ||||
-rw-r--r-- | sound/soc/omap/omap-mcbsp-priv.h | 324 | ||||
-rw-r--r-- | sound/soc/omap/omap-mcbsp-st.c | 516 | ||||
-rw-r--r-- | sound/soc/omap/omap-mcbsp.c | 1479 | ||||
-rw-r--r-- | sound/soc/omap/omap-mcbsp.h | 46 | ||||
-rw-r--r-- | sound/soc/omap/omap-mcpdm.c | 619 | ||||
-rw-r--r-- | sound/soc/omap/omap-mcpdm.h | 107 | ||||
-rw-r--r-- | sound/soc/omap/omap-twl4030.c | 353 | ||||
-rw-r--r-- | sound/soc/omap/omap3pandora.c | 315 | ||||
-rw-r--r-- | sound/soc/omap/osk5912.c | 187 | ||||
-rw-r--r-- | sound/soc/omap/rx51.c | 493 | ||||
-rw-r--r-- | sound/soc/omap/sdma-pcm.c | 74 | ||||
-rw-r--r-- | sound/soc/omap/sdma-pcm.h | 21 |
20 files changed, 0 insertions, 7037 deletions
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig deleted file mode 100644 index 3d418482d242..000000000000 --- a/sound/soc/omap/Kconfig +++ /dev/null @@ -1,120 +0,0 @@ -config SND_OMAP_SOC - tristate "SoC Audio for Texas Instruments OMAP chips (deprecated)" - depends on (ARCH_OMAP && DMA_OMAP) || (ARM && COMPILE_TEST) - select SND_SDMA_SOC - -config SND_SDMA_SOC - tristate "SoC Audio for Texas Instruments chips using sDMA" - depends on DMA_OMAP || COMPILE_TEST - select SND_SOC_GENERIC_DMAENGINE_PCM - -config SND_OMAP_SOC_DMIC - tristate - -config SND_OMAP_SOC_MCBSP - tristate - -config SND_OMAP_SOC_MCPDM - tristate - -config SND_OMAP_SOC_HDMI_AUDIO - tristate "HDMI audio support for OMAP4+ based SoCs" - depends on SND_SDMA_SOC - help - For HDMI audio to work OMAPDSS HDMI support should be - enabled. - The hdmi audio driver implements cpu-dai component using the - callbacks provided by OMAPDSS and registers the component - under DSS HDMI device. Omap-pcm is registered for platform - component also under DSS HDMI device. Dummy codec is used as - as codec component. The hdmi audio driver implements also - the card and registers it under its own platform device. - The device for the driver is registered by OMAPDSS hdmi - driver. - -config SND_OMAP_SOC_N810 - tristate "SoC Audio support for Nokia N810" - depends on SND_SDMA_SOC && MACH_NOKIA_N810 && I2C - select SND_OMAP_SOC_MCBSP - select SND_SOC_TLV320AIC3X - help - Say Y if you want to add support for SoC audio on Nokia N810. - -config SND_OMAP_SOC_RX51 - tristate "SoC Audio support for Nokia N900 (RX-51)" - depends on SND_SDMA_SOC && ARM && I2C - select SND_OMAP_SOC_MCBSP - select SND_SOC_TLV320AIC3X - select SND_SOC_TPA6130A2 - depends on GPIOLIB - help - Say Y if you want to add support for SoC audio on Nokia N900 - cellphone. - -config SND_OMAP_SOC_AMS_DELTA - tristate "SoC Audio support for Amstrad E3 (Delta) videophone" - depends on SND_SDMA_SOC && MACH_AMS_DELTA && TTY - select SND_OMAP_SOC_MCBSP - select SND_SOC_CX20442 - help - Say Y if you want to add support for SoC audio device connected to - a handset and a speakerphone found on Amstrad E3 (Delta) videophone. - - Note that in order to get those devices fully supported, you have to - build the kernel with standard serial port driver included and - configured for at least 4 ports. Then, from userspace, you must load - a line discipline #19 on the modem (ttyS3) serial line. The simplest - way to achieve this is to install util-linux-ng and use the included - ldattach utility. This can be started automatically from udev, - a simple rule like this one should do the trick (it does for me): - ACTION=="add", KERNEL=="controlC0", \ - RUN+="/usr/sbin/ldattach 19 /dev/ttyS3" - -config SND_OMAP_SOC_OSK5912 - tristate "SoC Audio support for omap osk5912" - depends on SND_SDMA_SOC && MACH_OMAP_OSK && I2C - select SND_OMAP_SOC_MCBSP - select SND_SOC_TLV320AIC23_I2C - help - Say Y if you want to add support for SoC audio on osk5912. - -config SND_OMAP_SOC_OMAP_TWL4030 - tristate "SoC Audio support for TI SoC based boards with twl4030 codec" - depends on TWL4030_CORE && SND_SDMA_SOC - select SND_OMAP_SOC_MCBSP - select SND_SOC_TWL4030 - help - Say Y if you want to add support for SoC audio on TI SoC based boards - using twl4030 as c codec. This driver currently supports: - - Beagleboard or Devkit8000 - - Gumstix Overo or CompuLab CM-T35/CM-T3730 - - IGEP v2 - - OMAP3EVM - - SDP3430 - - Zoom2 - -config SND_OMAP_SOC_OMAP_ABE_TWL6040 - tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" - depends on TWL6040_CORE && SND_SDMA_SOC && COMMON_CLK - depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST - select SND_OMAP_SOC_DMIC - select SND_OMAP_SOC_MCPDM - select SND_SOC_TWL6040 - select SND_SOC_DMIC - select COMMON_CLK_PALMAS if (SOC_OMAP5 && MFD_PALMAS) - select CLK_TWL6040 - help - Say Y if you want to add support for SoC audio on OMAP boards using - ABE and twl6040 codec. This driver currently supports: - - SDP4430/Blaze boards - - PandaBoard (4430) - - PandaBoardES (4460) - - omap5-uevm (5432) - -config SND_OMAP_SOC_OMAP3_PANDORA - tristate "SoC Audio support for OMAP3 Pandora" - depends on TWL4030_CORE && SND_SDMA_SOC && MACH_OMAP3_PANDORA - select SND_OMAP_SOC_MCBSP - select SND_SOC_TWL4030 - help - Say Y if you want to add support for SoC audio on the OMAP3 Pandora. diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile deleted file mode 100644 index d005338dd13c..000000000000 --- a/sound/soc/omap/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# OMAP Platform Support -snd-soc-sdma-objs := sdma-pcm.o -snd-soc-omap-dmic-objs := omap-dmic.o -snd-soc-omap-mcbsp-objs := omap-mcbsp.o omap-mcbsp-st.o -snd-soc-omap-mcpdm-objs := omap-mcpdm.o -snd-soc-omap-hdmi-audio-objs := omap-hdmi-audio.o - -obj-$(CONFIG_SND_SDMA_SOC) += snd-soc-sdma.o -obj-$(CONFIG_SND_OMAP_SOC_DMIC) += snd-soc-omap-dmic.o -obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o -obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o -obj-$(CONFIG_SND_OMAP_SOC_HDMI_AUDIO) += snd-soc-omap-hdmi-audio.o - -# OMAP Machine Support -snd-soc-n810-objs := n810.o -snd-soc-rx51-objs := rx51.o -snd-soc-ams-delta-objs := ams-delta.o -snd-soc-osk5912-objs := osk5912.o -snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o -snd-soc-omap-twl4030-objs := omap-twl4030.o -snd-soc-omap3pandora-objs := omap3pandora.o - -obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o -obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o -obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o -obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o -obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o -obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o -obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c deleted file mode 100644 index 4dce494dfbd3..000000000000 --- a/sound/soc/omap/ams-delta.c +++ /dev/null @@ -1,594 +0,0 @@ -/* - * ams-delta.c -- SoC audio for Amstrad E3 (Delta) videophone - * - * Copyright (C) 2009 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> - * - * Initially based on sound/soc/omap/osk5912.x - * Copyright (C) 2008 Mistral Solutions - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/gpio/consumer.h> -#include <linux/spinlock.h> -#include <linux/tty.h> -#include <linux/module.h> - -#include <sound/soc.h> -#include <sound/jack.h> - -#include <asm/mach-types.h> - -#include <linux/platform_data/asoc-ti-mcbsp.h> - -#include "omap-mcbsp.h" -#include "../codecs/cx20442.h" - -/* Board specific DAPM widgets */ -static const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = { - /* Handset */ - SND_SOC_DAPM_MIC("Mouthpiece", NULL), - SND_SOC_DAPM_HP("Earpiece", NULL), - /* Handsfree/Speakerphone */ - SND_SOC_DAPM_MIC("Microphone", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - -/* How they are connected to codec pins */ -static const struct snd_soc_dapm_route ams_delta_audio_map[] = { - {"TELIN", NULL, "Mouthpiece"}, - {"Earpiece", NULL, "TELOUT"}, - - {"MIC", NULL, "Microphone"}, - {"Speaker", NULL, "SPKOUT"}, -}; - -/* - * Controls, functional after the modem line discipline is activated. - */ - -/* Virtual switch: audio input/output constellations */ -static const char *ams_delta_audio_mode[] = - {"Mixed", "Handset", "Handsfree", "Speakerphone"}; - -/* Selection <-> pin translation */ -#define AMS_DELTA_MOUTHPIECE 0 -#define AMS_DELTA_EARPIECE 1 -#define AMS_DELTA_MICROPHONE 2 -#define AMS_DELTA_SPEAKER 3 -#define AMS_DELTA_AGC 4 - -#define AMS_DELTA_MIXED ((1 << AMS_DELTA_EARPIECE) | \ - (1 << AMS_DELTA_MICROPHONE)) -#define AMS_DELTA_HANDSET ((1 << AMS_DELTA_MOUTHPIECE) | \ - (1 << AMS_DELTA_EARPIECE)) -#define AMS_DELTA_HANDSFREE ((1 << AMS_DELTA_MICROPHONE) | \ - (1 << AMS_DELTA_SPEAKER)) -#define AMS_DELTA_SPEAKERPHONE (AMS_DELTA_HANDSFREE | (1 << AMS_DELTA_AGC)) - -static const unsigned short ams_delta_audio_mode_pins[] = { - AMS_DELTA_MIXED, - AMS_DELTA_HANDSET, - AMS_DELTA_HANDSFREE, - AMS_DELTA_SPEAKERPHONE, -}; - -static unsigned short ams_delta_audio_agc; - -/* - * Used for passing a codec structure pointer - * from the board initialization code to the tty line discipline. - */ -static struct snd_soc_component *cx20442_codec; - -static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_context *dapm = &card->dapm; - struct soc_enum *control = (struct soc_enum *)kcontrol->private_value; - unsigned short pins; - int pin, changed = 0; - - /* Refuse any mode changes if we are not able to control the codec. */ - if (!cx20442_codec->card->pop_time) - return -EUNATCH; - - if (ucontrol->value.enumerated.item[0] >= control->items) - return -EINVAL; - - snd_soc_dapm_mutex_lock(dapm); - - /* Translate selection to bitmap */ - pins = ams_delta_audio_mode_pins[ucontrol->value.enumerated.item[0]]; - - /* Setup pins after corresponding bits if changed */ - pin = !!(pins & (1 << AMS_DELTA_MOUTHPIECE)); - - if (pin != snd_soc_dapm_get_pin_status(dapm, "Mouthpiece")) { - changed = 1; - if (pin) - snd_soc_dapm_enable_pin_unlocked(dapm, "Mouthpiece"); - else - snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece"); - } - pin = !!(pins & (1 << AMS_DELTA_EARPIECE)); - if (pin != snd_soc_dapm_get_pin_status(dapm, "Earpiece")) { - changed = 1; - if (pin) - snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece"); - else - snd_soc_dapm_disable_pin_unlocked(dapm, "Earpiece"); - } - pin = !!(pins & (1 << AMS_DELTA_MICROPHONE)); - if (pin != snd_soc_dapm_get_pin_status(dapm, "Microphone")) { - changed = 1; - if (pin) - snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone"); - else - snd_soc_dapm_disable_pin_unlocked(dapm, "Microphone"); - } - pin = !!(pins & (1 << AMS_DELTA_SPEAKER)); - if (pin != snd_soc_dapm_get_pin_status(dapm, "Speaker")) { - changed = 1; - if (pin) - snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker"); - else - snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker"); - } - pin = !!(pins & (1 << AMS_DELTA_AGC)); - if (pin != ams_delta_audio_agc) { - ams_delta_audio_agc = pin; - changed = 1; - if (pin) - snd_soc_dapm_enable_pin_unlocked(dapm, "AGCIN"); - else - snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN"); - } - - if (changed) - snd_soc_dapm_sync_unlocked(dapm); - - snd_soc_dapm_mutex_unlock(dapm); - - return changed; -} - -static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_context *dapm = &card->dapm; - unsigned short pins, mode; - - pins = ((snd_soc_dapm_get_pin_status(dapm, "Mouthpiece") << - AMS_DELTA_MOUTHPIECE) | - (snd_soc_dapm_get_pin_status(dapm, "Earpiece") << - AMS_DELTA_EARPIECE)); - if (pins) - pins |= (snd_soc_dapm_get_pin_status(dapm, "Microphone") << - AMS_DELTA_MICROPHONE); - else - pins = ((snd_soc_dapm_get_pin_status(dapm, "Microphone") << - AMS_DELTA_MICROPHONE) | - (snd_soc_dapm_get_pin_status(dapm, "Speaker") << - AMS_DELTA_SPEAKER) | - (ams_delta_audio_agc << AMS_DELTA_AGC)); - - for (mode = 0; mode < ARRAY_SIZE(ams_delta_audio_mode); mode++) - if (pins == ams_delta_audio_mode_pins[mode]) - break; - - if (mode >= ARRAY_SIZE(ams_delta_audio_mode)) - return -EINVAL; - - ucontrol->value.enumerated.item[0] = mode; - - return 0; -} - -static const SOC_ENUM_SINGLE_EXT_DECL(ams_delta_audio_enum, - ams_delta_audio_mode); - -static const struct snd_kcontrol_new ams_delta_audio_controls[] = { - SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum, - ams_delta_get_audio_mode, ams_delta_set_audio_mode), -}; - -/* Hook switch */ -static struct snd_soc_jack ams_delta_hook_switch; -static struct snd_soc_jack_gpio ams_delta_hook_switch_gpios[] = { - { - .name = "hook_switch", - .report = SND_JACK_HEADSET, - .invert = 1, - .debounce_time = 150, - } -}; - -/* After we are able to control the codec over the modem, - * the hook switch can be used for dynamic DAPM reconfiguration. */ -static struct snd_soc_jack_pin ams_delta_hook_switch_pins[] = { - /* Handset */ - { - .pin = "Mouthpiece", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Earpiece", - .mask = SND_JACK_HEADPHONE, - }, - /* Handsfree */ - { - .pin = "Microphone", - .mask = SND_JACK_MICROPHONE, - .invert = 1, - }, - { - .pin = "Speaker", - .mask = SND_JACK_HEADPHONE, - .invert = 1, - }, -}; - - -/* - * Modem line discipline, required for making above controls functional. - * Activated from userspace with ldattach, possibly invoked from udev rule. - */ - -/* To actually apply any modem controlled configuration changes to the codec, - * we must connect codec DAI pins to the modem for a moment. Be careful not - * to interfere with our digital mute function that shares the same hardware. */ -static struct timer_list cx81801_timer; -static bool cx81801_cmd_pending; -static bool ams_delta_muted; -static DEFINE_SPINLOCK(ams_delta_lock); -static struct gpio_desc *gpiod_modem_codec; - -static void cx81801_timeout(struct timer_list *unused) -{ - int muted; - - spin_lock(&ams_delta_lock); - cx81801_cmd_pending = 0; - muted = ams_delta_muted; - spin_unlock(&ams_delta_lock); - - /* Reconnect the codec DAI back from the modem to the CPU DAI - * only if digital mute still off */ - if (!muted) - gpiod_set_value(gpiod_modem_codec, 0); -} - -/* Line discipline .open() */ -static int cx81801_open(struct tty_struct *tty) -{ - int ret; - - if (!cx20442_codec) - return -ENODEV; - - /* - * Pass the codec structure pointer for use by other ldisc callbacks, - * both the card and the codec specific parts. - */ - tty->disc_data = cx20442_codec; - - ret = v253_ops.open(tty); - - if (ret < 0) - tty->disc_data = NULL; - - return ret; -} - -/* Line discipline .close() */ -static void cx81801_close(struct tty_struct *tty) -{ - struct snd_soc_component *component = tty->disc_data; - struct snd_soc_dapm_context *dapm = &component->card->dapm; - - del_timer_sync(&cx81801_timer); - - /* Prevent the hook switch from further changing the DAPM pins */ - INIT_LIST_HEAD(&ams_delta_hook_switch.pins); - - if (!component) - return; - - v253_ops.close(tty); - - /* Revert back to default audio input/output constellation */ - snd_soc_dapm_mutex_lock(dapm); - - snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece"); - snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece"); - snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone"); - snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker"); - snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN"); - - snd_soc_dapm_sync_unlocked(dapm); - - snd_soc_dapm_mutex_unlock(dapm); -} - -/* Line discipline .hangup() */ -static int cx81801_hangup(struct tty_struct *tty) -{ - cx81801_close(tty); - return 0; -} - -/* Line discipline .receive_buf() */ -static void cx81801_receive(struct tty_struct *tty, - const unsigned char *cp, char *fp, int count) -{ - struct snd_soc_component *component = tty->disc_data; - const unsigned char *c; - int apply, ret; - - if (!component) - return; - - if (!component->card->pop_time) { - /* First modem response, complete setup procedure */ - - /* Initialize timer used for config pulse generation */ - timer_setup(&cx81801_timer, cx81801_timeout, 0); - - v253_ops.receive_buf(tty, cp, fp, count); - - /* Link hook switch to DAPM pins */ - ret = snd_soc_jack_add_pins(&ams_delta_hook_switch, - ARRAY_SIZE(ams_delta_hook_switch_pins), - ams_delta_hook_switch_pins); - if (ret) - dev_warn(component->dev, - "Failed to link hook switch to DAPM pins, " - "will continue with hook switch unlinked.\n"); - - return; - } - - v253_ops.receive_buf(tty, cp, fp, count); - - for (c = &cp[count - 1]; c >= cp; c--) { - if (*c != '\r') - continue; - /* Complete modem response received, apply config to codec */ - - spin_lock_bh(&ams_delta_lock); - mod_timer(&cx81801_timer, jiffies + msecs_to_jiffies(150)); - apply = !ams_delta_muted && !cx81801_cmd_pending; - cx81801_cmd_pending = 1; - spin_unlock_bh(&ams_delta_lock); - - /* Apply config pulse by connecting the codec to the modem - * if not already done */ - if (apply) - gpiod_set_value(gpiod_modem_codec, 1); - break; - } -} - -/* Line discipline .write_wakeup() */ -static void cx81801_wakeup(struct tty_struct *tty) -{ - v253_ops.write_wakeup(tty); -} - -static struct tty_ldisc_ops cx81801_ops = { - .magic = TTY_LDISC_MAGIC, - .name = "cx81801", - .owner = THIS_MODULE, - .open = cx81801_open, - .close = cx81801_close, - .hangup = cx81801_hangup, - .receive_buf = cx81801_receive, - .write_wakeup = cx81801_wakeup, -}; - - -/* - * Even if not very useful, the sound card can still work without any of the - * above functonality activated. You can still control its audio input/output - * constellation and speakerphone gain from userspace by issuing AT commands - * over the modem port. - */ - -static struct snd_soc_ops ams_delta_ops; - - -/* Digital mute implemented using modem/CPU multiplexer. - * Shares hardware with codec config pulse generation */ -static bool ams_delta_muted = 1; - -static int ams_delta_digital_mute(struct snd_soc_dai *dai, int mute) -{ - int apply; - - if (ams_delta_muted == mute) - return 0; - - spin_lock_bh(&ams_delta_lock); - ams_delta_muted = mute; - apply = !cx81801_cmd_pending; - spin_unlock_bh(&ams_delta_lock); - - if (apply) - gpiod_set_value(gpiod_modem_codec, !!mute); - return 0; -} - -/* Our codec DAI probably doesn't have its own .ops structure */ -static const struct snd_soc_dai_ops ams_delta_dai_ops = { - .digital_mute = ams_delta_digital_mute, -}; - -/* Will be used if the codec ever has its own digital_mute function */ -static int ams_delta_startup(struct snd_pcm_substream *substream) -{ - return ams_delta_digital_mute(NULL, 0); -} - -static void ams_delta_shutdown(struct snd_pcm_substream *substream) -{ - ams_delta_digital_mute(NULL, 1); -} - - -/* - * Card initialization - */ - -static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_card *card = rtd->card; - struct snd_soc_dapm_context *dapm = &card->dapm; - int ret; - /* Codec is ready, now add/activate board specific controls */ - - /* Store a pointer to the codec structure for tty ldisc use */ - cx20442_codec = rtd->codec_dai->component; - - /* Add hook switch - can be used to control the codec from userspace - * even if line discipline fails */ - ret = snd_soc_card_jack_new(card, "hook_switch", SND_JACK_HEADSET, - &ams_delta_hook_switch, NULL, 0); - if (ret) - dev_warn(card->dev, - "Failed to allocate resources for hook switch, " - "will continue without one.\n"); - else { - ret = snd_soc_jack_add_gpiods(card->dev, &ams_delta_hook_switch, - ARRAY_SIZE(ams_delta_hook_switch_gpios), - ams_delta_hook_switch_gpios); - if (ret) - dev_warn(card->dev, - "Failed to set up hook switch GPIO line, " - "will continue with hook switch inactive.\n"); - } - - gpiod_modem_codec = devm_gpiod_get(card->dev, "modem_codec", - GPIOD_OUT_HIGH); - if (IS_ERR(gpiod_modem_codec)) { - dev_warn(card->dev, "Failed to obtain modem_codec GPIO\n"); - return 0; - } - - /* Set up digital mute if not provided by the codec */ - if (!codec_dai->driver->ops) { - codec_dai->driver->ops = &ams_delta_dai_ops; - } else { - ams_delta_ops.startup = ams_delta_startup; - ams_delta_ops.shutdown = ams_delta_shutdown; - } - - /* Register optional line discipline for over the modem control */ - ret = tty_register_ldisc(N_V253, &cx81801_ops); - if (ret) { - dev_warn(card->dev, - "Failed to register line discipline, " - "will continue without any controls.\n"); - return 0; - } - - /* Set up initial pin constellation */ - snd_soc_dapm_disable_pin(dapm, "Mouthpiece"); - snd_soc_dapm_disable_pin(dapm, "Speaker"); - snd_soc_dapm_disable_pin(dapm, "AGCIN"); - snd_soc_dapm_disable_pin(dapm, "AGCOUT"); - - return 0; -} - -/* DAI glue - connects codec <--> CPU */ -static struct snd_soc_dai_link ams_delta_dai_link = { - .name = "CX20442", - .stream_name = "CX20442", - .cpu_dai_name = "omap-mcbsp.1", - .codec_dai_name = "cx20442-voice", - .init = ams_delta_cx20442_init, - .platform_name = "omap-mcbsp.1", - .codec_name = "cx20442-codec", - .ops = &ams_delta_ops, - .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, -}; - -/* Audio card driver */ -static struct snd_soc_card ams_delta_audio_card = { - .name = "AMS_DELTA", - .owner = THIS_MODULE, - .dai_link = &ams_delta_dai_link, - .num_links = 1, - - .controls = ams_delta_audio_controls, - .num_controls = ARRAY_SIZE(ams_delta_audio_controls), - .dapm_widgets = ams_delta_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ams_delta_dapm_widgets), - .dapm_routes = ams_delta_audio_map, - .num_dapm_routes = ARRAY_SIZE(ams_delta_audio_map), -}; - -/* Module init/exit */ -static int ams_delta_probe(struct platform_device *pdev) -{ - struct snd_soc_card *card = &ams_delta_audio_card; - int ret; - - card->dev = &pdev->dev; - - ret = snd_soc_register_card(card); - if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); - card->dev = NULL; - return ret; - } - return 0; -} - -static int ams_delta_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - if (tty_unregister_ldisc(N_V253) != 0) - dev_warn(&pdev->dev, - "failed to unregister V253 line discipline\n"); - - snd_soc_unregister_card(card); - card->dev = NULL; - return 0; -} - -#define DRV_NAME "ams-delta-audio" - -static struct platform_driver ams_delta_driver = { - .driver = { - .name = DRV_NAME, - }, - .probe = ams_delta_probe, - .remove = ams_delta_remove, -}; - -module_platform_driver(ams_delta_driver); - -MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>"); -MODULE_DESCRIPTION("ALSA SoC driver for Amstrad E3 (Delta) videophone"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c deleted file mode 100644 index 9cfefe44a75f..000000000000 --- a/sound/soc/omap/n810.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * n810.c -- SoC audio for Nokia N810 - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/i2c.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> - -#include <asm/mach-types.h> -#include <linux/gpio.h> -#include <linux/module.h> -#include <linux/platform_data/asoc-ti-mcbsp.h> - -#include "omap-mcbsp.h" - -#define N810_HEADSET_AMP_GPIO 10 -#define N810_SPEAKER_AMP_GPIO 101 - -enum { - N810_JACK_DISABLED, - N810_JACK_HP, - N810_JACK_HS, - N810_JACK_MIC, -}; - -static struct clk *sys_clkout2; -static struct clk *sys_clkout2_src; -static struct clk *func96m_clk; - -static int n810_spk_func; -static int n810_jack_func; -static int n810_dmic_func; - -static void n810_ext_control(struct snd_soc_dapm_context *dapm) -{ - int hp = 0, line1l = 0; - - switch (n810_jack_func) { - case N810_JACK_HS: - line1l = 1; - case N810_JACK_HP: - hp = 1; - break; - case N810_JACK_MIC: - line1l = 1; - break; - } - - snd_soc_dapm_mutex_lock(dapm); - - if (n810_spk_func) - snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); - else - snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); - - if (hp) - snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); - else - snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); - if (line1l) - snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic"); - else - snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic"); - - if (n810_dmic_func) - snd_soc_dapm_enable_pin_unlocked(dapm, "DMic"); - else - snd_soc_dapm_disable_pin_unlocked(dapm, "DMic"); - - snd_soc_dapm_sync_unlocked(dapm); - - snd_soc_dapm_mutex_unlock(dapm); -} - -static int n810_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - - snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2); - - n810_ext_control(&rtd->card->dapm); - return clk_prepare_enable(sys_clkout2); -} - -static void n810_shutdown(struct snd_pcm_substream *substream) -{ - clk_disable_unprepare(sys_clkout2); -} - -static int n810_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->codec_dai; - int err; - - /* Set the codec system clock for DAC and ADC */ - err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000, - SND_SOC_CLOCK_IN); - - return err; -} - -static const struct snd_soc_ops n810_ops = { - .startup = n810_startup, - .hw_params = n810_hw_params, - .shutdown = n810_shutdown, -}; - -static int n810_get_spk(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = n810_spk_func; - - return 0; -} - -static int n810_set_spk(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); - - if (n810_spk_func == ucontrol->value.enumerated.item[0]) - return 0; - - n810_spk_func = ucontrol->value.enumerated.item[0]; - n810_ext_control(&card->dapm); - - return 1; -} - -static int n810_get_jack(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = n810_jack_func; - - return 0; -} - -static int n810_set_jack(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); - - if (n810_jack_func == ucontrol->value.enumerated.item[0]) - return 0; - - n810_jack_func = ucontrol->value.enumerated.item[0]; - n810_ext_control(&card->dapm); - - return 1; -} - -static int n810_get_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = n810_dmic_func; - - return 0; -} - -static int n810_set_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); - - if (n810_dmic_func == ucontrol->value.enumerated.item[0]) - return 0; - - n810_dmic_func = ucontrol->value.enumerated.item[0]; - n810_ext_control(&card->dapm); - - return 1; -} - -static int n810_spk_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - if (SND_SOC_DAPM_EVENT_ON(event)) - gpio_set_value(N810_SPEAKER_AMP_GPIO, 1); - else - gpio_set_value(N810_SPEAKER_AMP_GPIO, 0); - - return 0; -} - -static int n810_jack_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - if (SND_SOC_DAPM_EVENT_ON(event)) - gpio_set_value(N810_HEADSET_AMP_GPIO, 1); - else - gpio_set_value(N810_HEADSET_AMP_GPIO, 0); - - return 0; -} - -static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = { - SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event), - SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event), - SND_SOC_DAPM_MIC("DMic", NULL), - SND_SOC_DAPM_MIC("HS Mic", NULL), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - {"Headphone Jack", NULL, "HPLOUT"}, - {"Headphone Jack", NULL, "HPROUT"}, - - {"Ext Spk", NULL, "LLOUT"}, - {"Ext Spk", NULL, "RLOUT"}, - - {"DMic Rate 64", NULL, "DMic"}, - {"DMic", NULL, "Mic Bias"}, - - /* - * Note that the mic bias is coming from Retu/Vilma and we don't have - * control over it atm. The analog HS mic is not working. <- TODO - */ - {"LINE1L", NULL, "HS Mic"}, -}; - -static const char *spk_function[] = {"Off", "On"}; -static const char *jack_function[] = {"Off", "Headphone", "Headset", "Mic"}; -static const char *input_function[] = {"ADC", "Digital Mic"}; -static const struct soc_enum n810_enum[] = { - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), -}; - -static const struct snd_kcontrol_new aic33_n810_controls[] = { - SOC_ENUM_EXT("Speaker Function", n810_enum[0], - n810_get_spk, n810_set_spk), - SOC_ENUM_EXT("Jack Function", n810_enum[1], - n810_get_jack, n810_set_jack), - SOC_ENUM_EXT("Input Select", n810_enum[2], - n810_get_input, n810_set_input), -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link n810_dai = { - .name = "TLV320AIC33", - .stream_name = "AIC33", - .cpu_dai_name = "48076000.mcbsp", - .platform_name = "48076000.mcbsp", - .codec_name = "tlv320aic3x-codec.1-0018", - .codec_dai_name = "tlv320aic3x-hifi", - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, - .ops = &n810_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_n810 = { - .name = "N810", - .owner = THIS_MODULE, - .dai_link = &n810_dai, - .num_links = 1, - - .controls = aic33_n810_controls, - .num_controls = ARRAY_SIZE(aic33_n810_controls), - .dapm_widgets = aic33_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(aic33_dapm_widgets), - .dapm_routes = audio_map, - .num_dapm_routes = ARRAY_SIZE(audio_map), - .fully_routed = true, -}; - -static struct platform_device *n810_snd_device; - -static int __init n810_soc_init(void) -{ - int err; - struct device *dev; - - if (!of_have_populated_dt() || - (!of_machine_is_compatible("nokia,n810") && - !of_machine_is_compatible("nokia,n810-wimax"))) - return -ENODEV; - - n810_snd_device = platform_device_alloc("soc-audio", -1); - if (!n810_snd_device) - return -ENOMEM; - - platform_set_drvdata(n810_snd_device, &snd_soc_n810); - err = platform_device_add(n810_snd_device); - if (err) - goto err1; - - dev = &n810_snd_device->dev; - - sys_clkout2_src = clk_get(dev, "sys_clkout2_src"); - if (IS_ERR(sys_clkout2_src)) { - dev_err(dev, "Could not get sys_clkout2_src clock\n"); - err = PTR_ERR(sys_clkout2_src); - goto err2; - } - sys_clkout2 = clk_get(dev, "sys_clkout2"); - if (IS_ERR(sys_clkout2)) { - dev_err(dev, "Could not get sys_clkout2\n"); - err = PTR_ERR(sys_clkout2); - goto err3; - } - /* - * Configure 12 MHz output on SYS_CLKOUT2. Therefore we must use - * 96 MHz as its parent in order to get 12 MHz - */ - func96m_clk = clk_get(dev, "func_96m_ck"); - if (IS_ERR(func96m_clk)) { - dev_err(dev, "Could not get func 96M clock\n"); - err = PTR_ERR(func96m_clk); - goto err4; - } - clk_set_parent(sys_clkout2_src, func96m_clk); - clk_set_rate(sys_clkout2, 12000000); - - if (WARN_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) || - (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0))) { - err = -EINVAL; - goto err4; - } - - gpio_direction_output(N810_HEADSET_AMP_GPIO, 0); - gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0); - - return 0; -err4: - clk_put(sys_clkout2); -err3: - clk_put(sys_clkout2_src); -err2: - platform_device_del(n810_snd_device); -err1: - platform_device_put(n810_snd_device); - - return err; -} - -static void __exit n810_soc_exit(void) -{ - gpio_free(N810_SPEAKER_AMP_GPIO); - gpio_free(N810_HEADSET_AMP_GPIO); - clk_put(sys_clkout2_src); - clk_put(sys_clkout2); - clk_put(func96m_clk); - - platform_device_unregister(n810_snd_device); -} - -module_init(n810_soc_init); -module_exit(n810_soc_exit); - -MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>"); -MODULE_DESCRIPTION("ALSA SoC Nokia N810"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c deleted file mode 100644 index fed45b41f9d3..000000000000 --- a/sound/soc/omap/omap-abe-twl6040.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * omap-abe-twl6040.c -- SoC audio for TI OMAP based boards with ABE and - * twl6040 codec - * - * Author: Misael Lopez Cruz <misael.lopez@ti.com> - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/mfd/twl6040.h> -#include <linux/module.h> -#include <linux/of.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/jack.h> - -#include "omap-dmic.h" -#include "omap-mcpdm.h" -#include "../codecs/twl6040.h" - -struct abe_twl6040 { - struct snd_soc_card card; - struct snd_soc_dai_link dai_links[2]; - int jack_detection; /* board can detect jack events */ - int mclk_freq; /* MCLK frequency speed for twl6040 */ -}; - -static struct platform_device *dmic_codec_dev; - -static int omap_abe_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->codec_dai; - struct snd_soc_card *card = rtd->card; - struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); - int clk_id, freq; - int ret; - - clk_id = twl6040_get_clk_id(codec_dai->component); - if (clk_id == TWL6040_SYSCLK_SEL_HPPLL) - freq = priv->mclk_freq; - else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL) - freq = 32768; - else - return -EINVAL; - - /* set the codec mclk */ - ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq, - SND_SOC_CLOCK_IN); - if (ret) { - printk(KERN_ERR "can't set codec system clock\n"); - return ret; - } - return ret; -} - -static const struct snd_soc_ops omap_abe_ops = { - .hw_params = omap_abe_hw_params, -}; - -static int omap_abe_dmic_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 *cpu_dai = rtd->cpu_dai; - int ret = 0; - - ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_SYSCLK_PAD_CLKS, - 19200000, SND_SOC_CLOCK_IN); - if (ret < 0) { - printk(KERN_ERR "can't set DMIC cpu system clock\n"); - return ret; - } - ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_ABE_DMIC_CLK, 2400000, - SND_SOC_CLOCK_OUT); - if (ret < 0) { - printk(KERN_ERR "can't set DMIC output clock\n"); - return ret; - } - return 0; -} - -static struct snd_soc_ops omap_abe_dmic_ops = { - .hw_params = omap_abe_dmic_hw_params, -}; - -/* Headset jack */ -static struct snd_soc_jack hs_jack; - -/*Headset jack detection DAPM pins */ -static struct snd_soc_jack_pin hs_jack_pins[] = { - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Headset Stereophone", - .mask = SND_JACK_HEADPHONE, - }, -}; - -/* SDP4430 machine DAPM */ -static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { - /* Outputs */ - SND_SOC_DAPM_HP("Headset Stereophone", NULL), - SND_SOC_DAPM_SPK("Earphone Spk", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), - SND_SOC_DAPM_LINE("Line Out", NULL), - SND_SOC_DAPM_SPK("Vibrator", NULL), - - /* Inputs */ - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Main Handset Mic", NULL), - SND_SOC_DAPM_MIC("Sub Handset Mic", NULL), - SND_SOC_DAPM_LINE("Line In", NULL), - - /* Digital microphones */ - SND_SOC_DAPM_MIC("Digital Mic", NULL), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - /* Routings for outputs */ - {"Headset Stereophone", NULL, "HSOL"}, - {"Headset Stereophone", NULL, "HSOR"}, - - {"Earphone Spk", NULL, "EP"}, - - {"Ext Spk", NULL, "HFL"}, - {"Ext Spk", NULL, "HFR"}, - - {"Line Out", NULL, "AUXL"}, - {"Line Out", NULL, "AUXR"}, - - {"Vibrator", NULL, "VIBRAL"}, - {"Vibrator", NULL, "VIBRAR"}, - - /* Routings for inputs */ - {"HSMIC", NULL, "Headset Mic"}, - {"Headset Mic", NULL, "Headset Mic Bias"}, - - {"MAINMIC", NULL, "Main Handset Mic"}, - {"Main Handset Mic", NULL, "Main Mic Bias"}, - - {"SUBMIC", NULL, "Sub Handset Mic"}, - {"Sub Handset Mic", NULL, "Main Mic Bias"}, - - {"AFML", NULL, "Line In"}, - {"AFMR", NULL, "Line In"}, -}; - -static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = rtd->codec_dai->component; - struct snd_soc_card *card = rtd->card; - struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); - int hs_trim; - int ret = 0; - - /* - * Configure McPDM offset cancellation based on the HSOTRIM value from - * twl6040. - */ - hs_trim = twl6040_get_trim_value(component, TWL6040_TRIM_HSOTRIM); - omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim), - TWL6040_HSF_TRIM_RIGHT(hs_trim)); - - /* Headset jack detection only if it is supported */ - if (priv->jack_detection) { - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET, &hs_jack, - hs_jack_pins, - ARRAY_SIZE(hs_jack_pins)); - if (ret) - return ret; - - twl6040_hs_jack_detect(component, &hs_jack, SND_JACK_HEADSET); - } - - return 0; -} - -static const struct snd_soc_dapm_route dmic_audio_map[] = { - {"DMic", NULL, "Digital Mic"}, - {"Digital Mic", NULL, "Digital Mic1 Bias"}, -}; - -static int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm = &rtd->card->dapm; - - return snd_soc_dapm_add_routes(dapm, dmic_audio_map, - ARRAY_SIZE(dmic_audio_map)); -} - -static int omap_abe_probe(struct platform_device *pdev) -{ - struct device_node *node = pdev->dev.of_node; - struct snd_soc_card *card; - struct device_node *dai_node; - struct abe_twl6040 *priv; - int num_links = 0; - int ret = 0; - - if (!node) { - dev_err(&pdev->dev, "of node is missing.\n"); - return -ENODEV; - } - - priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; - - card = &priv->card; - card->dev = &pdev->dev; - card->owner = THIS_MODULE; - card->dapm_widgets = twl6040_dapm_widgets; - card->num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets); - card->dapm_routes = audio_map; - card->num_dapm_routes = ARRAY_SIZE(audio_map); - - if (snd_soc_of_parse_card_name(card, "ti,model")) { - dev_err(&pdev->dev, "Card name is not provided\n"); - return -ENODEV; - } - - ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing"); - if (ret) { - dev_err(&pdev->dev, "Error while parsing DAPM routing\n"); - return ret; - } - - dai_node = of_parse_phandle(node, "ti,mcpdm", 0); - if (!dai_node) { - dev_err(&pdev->dev, "McPDM node is not provided\n"); - return -EINVAL; - } - - priv->dai_links[0].name = "DMIC"; - priv->dai_links[0].stream_name = "TWL6040"; - priv->dai_links[0].cpu_of_node = dai_node; - priv->dai_links[0].platform_of_node = dai_node; - priv->dai_links[0].codec_dai_name = "twl6040-legacy"; - priv->dai_links[0].codec_name = "twl6040-codec"; - priv->dai_links[0].init = omap_abe_twl6040_init; - priv->dai_links[0].ops = &omap_abe_ops; - - dai_node = of_parse_phandle(node, "ti,dmic", 0); - if (dai_node) { - num_links = 2; - priv->dai_links[1].name = "TWL6040"; - priv->dai_links[1].stream_name = "DMIC Capture"; - priv->dai_links[1].cpu_of_node = dai_node; - priv->dai_links[1].platform_of_node = dai_node; - priv->dai_links[1].codec_dai_name = "dmic-hifi"; - priv->dai_links[1].codec_name = "dmic-codec"; - priv->dai_links[1].init = omap_abe_dmic_init; - priv->dai_links[1].ops = &omap_abe_dmic_ops; - } else { - num_links = 1; - } - - priv->jack_detection = of_property_read_bool(node, "ti,jack-detection"); - of_property_read_u32(node, "ti,mclk-freq", &priv->mclk_freq); - if (!priv->mclk_freq) { - dev_err(&pdev->dev, "MCLK frequency not provided\n"); - return -EINVAL; - } - - card->fully_routed = 1; - - if (!priv->mclk_freq) { - dev_err(&pdev->dev, "MCLK frequency missing\n"); - return -ENODEV; - } - - card->dai_link = priv->dai_links; - card->num_links = num_links; - - snd_soc_card_set_drvdata(card, priv); - - ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) - dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n", - ret); - - return ret; -} - -static const struct of_device_id omap_abe_of_match[] = { - {.compatible = "ti,abe-twl6040", }, - { }, -}; -MODULE_DEVICE_TABLE(of, omap_abe_of_match); - -static struct platform_driver omap_abe_driver = { - .driver = { - .name = "omap-abe-twl6040", - .pm = &snd_soc_pm_ops, - .of_match_table = omap_abe_of_match, - }, - .probe = omap_abe_probe, -}; - -static int __init omap_abe_init(void) -{ - int ret; - - dmic_codec_dev = platform_device_register_simple("dmic-codec", -1, NULL, - 0); - if (IS_ERR(dmic_codec_dev)) { - pr_err("%s: dmic-codec device registration failed\n", __func__); - return PTR_ERR(dmic_codec_dev); - } - - ret = platform_driver_register(&omap_abe_driver); - if (ret) { - pr_err("%s: platform driver registration failed\n", __func__); - platform_device_unregister(dmic_codec_dev); - } - - return ret; -} -module_init(omap_abe_init); - -static void __exit omap_abe_exit(void) -{ - platform_driver_unregister(&omap_abe_driver); - platform_device_unregister(dmic_codec_dev); -} -module_exit(omap_abe_exit); - -MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); -MODULE_DESCRIPTION("ALSA SoC for OMAP boards with ABE and twl6040 codec"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:omap-abe-twl6040"); diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c deleted file mode 100644 index cba9645b6487..000000000000 --- a/sound/soc/omap/omap-dmic.c +++ /dev/null @@ -1,541 +0,0 @@ -/* - * omap-dmic.c -- OMAP ASoC DMIC DAI driver - * - * Copyright (C) 2010 - 2011 Texas Instruments - * - * Author: David Lambert <dlambert@ti.com> - * Misael Lopez Cruz <misael.lopez@ti.com> - * Liam Girdwood <lrg@ti.com> - * Peter Ujfalusi <peter.ujfalusi@ti.com> - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/pm_runtime.h> -#include <linux/of_device.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/initval.h> -#include <sound/soc.h> -#include <sound/dmaengine_pcm.h> - -#include "omap-dmic.h" -#include "sdma-pcm.h" - -struct omap_dmic { - struct device *dev; - void __iomem *io_base; - struct clk *fclk; - struct pm_qos_request pm_qos_req; - int latency; - int fclk_freq; - int out_freq; - int clk_div; - int sysclk; - int threshold; - u32 ch_enabled; - bool active; - struct mutex mutex; - - struct snd_dmaengine_dai_dma_data dma_data; -}; - -static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val) -{ - writel_relaxed(val, dmic->io_base + reg); -} - -static inline int omap_dmic_read(struct omap_dmic *dmic, u16 reg) -{ - return readl_relaxed(dmic->io_base + reg); -} - -static inline void omap_dmic_start(struct omap_dmic *dmic) -{ - u32 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG); - - /* Configure DMA controller */ - omap_dmic_write(dmic, OMAP_DMIC_DMAENABLE_SET_REG, - OMAP_DMIC_DMA_ENABLE); - - omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, ctrl | dmic->ch_enabled); -} - -static inline void omap_dmic_stop(struct omap_dmic *dmic) -{ - u32 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG); - omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, - ctrl & ~OMAP_DMIC_UP_ENABLE_MASK); - - /* Disable DMA request generation */ - omap_dmic_write(dmic, OMAP_DMIC_DMAENABLE_CLR_REG, - OMAP_DMIC_DMA_ENABLE); - -} - -static inline int dmic_is_enabled(struct omap_dmic *dmic) -{ - return omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG) & - OMAP_DMIC_UP_ENABLE_MASK; -} - -static int omap_dmic_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); - int ret = 0; - - mutex_lock(&dmic->mutex); - - if (!dai->active) - dmic->active = 1; - else - ret = -EBUSY; - - mutex_unlock(&dmic->mutex); - - return ret; -} - -static void omap_dmic_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); - - mutex_lock(&dmic->mutex); - - pm_qos_remove_request(&dmic->pm_qos_req); - - if (!dai->active) - dmic->active = 0; - - mutex_unlock(&dmic->mutex); -} - -static int omap_dmic_select_divider(struct omap_dmic *dmic, int sample_rate) -{ - int divider = -EINVAL; - - /* - * 192KHz rate is only supported with 19.2MHz/3.84MHz clock - * configuration. - */ - if (sample_rate == 192000) { - if (dmic->fclk_freq == 19200000 && dmic->out_freq == 3840000) - divider = 0x6; /* Divider: 5 (192KHz sampling rate) */ - else - dev_err(dmic->dev, - "invalid clock configuration for 192KHz\n"); - - return divider; - } - - switch (dmic->out_freq) { - case 1536000: - if (dmic->fclk_freq != 24576000) - goto div_err; - divider = 0x4; /* Divider: 16 */ - break; - case 2400000: - switch (dmic->fclk_freq) { - case 12000000: - divider = 0x5; /* Divider: 5 */ - break; - case 19200000: - divider = 0x0; /* Divider: 8 */ - break; - case 24000000: - divider = 0x2; /* Divider: 10 */ - break; - default: - goto div_err; - } - break; - case 3072000: - if (dmic->fclk_freq != 24576000) - goto div_err; - divider = 0x3; /* Divider: 8 */ - break; - case 3840000: - if (dmic->fclk_freq != 19200000) - goto div_err; - divider = 0x1; /* Divider: 5 (96KHz sampling rate) */ - break; - default: - dev_err(dmic->dev, "invalid out frequency: %dHz\n", - dmic->out_freq); - break; - } - - return divider; - -div_err: - dev_err(dmic->dev, "invalid out frequency %dHz for %dHz input\n", - dmic->out_freq, dmic->fclk_freq); - return -EINVAL; -} - -static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); - struct snd_dmaengine_dai_dma_data *dma_data; - int channels; - - dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params)); - if (dmic->clk_div < 0) { - dev_err(dmic->dev, "no valid divider for %dHz from %dHz\n", - dmic->out_freq, dmic->fclk_freq); - return -EINVAL; - } - - dmic->ch_enabled = 0; - channels = params_channels(params); - switch (channels) { - case 6: - dmic->ch_enabled |= OMAP_DMIC_UP3_ENABLE; - /* fall through */ - case 4: - dmic->ch_enabled |= OMAP_DMIC_UP2_ENABLE; - /* fall through */ - case 2: - dmic->ch_enabled |= OMAP_DMIC_UP1_ENABLE; - break; - default: - dev_err(dmic->dev, "invalid number of legacy channels\n"); - return -EINVAL; - } - - /* packet size is threshold * channels */ - dma_data = snd_soc_dai_get_dma_data(dai, substream); - dma_data->maxburst = dmic->threshold * channels; - dmic->latency = (OMAP_DMIC_THRES_MAX - dmic->threshold) * USEC_PER_SEC / - params_rate(params); - - return 0; -} - -static int omap_dmic_dai_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); - u32 ctrl; - - if (pm_qos_request_active(&dmic->pm_qos_req)) - pm_qos_update_request(&dmic->pm_qos_req, dmic->latency); - - /* Configure uplink threshold */ - omap_dmic_write(dmic, OMAP_DMIC_FIFO_CTRL_REG, dmic->threshold); - - ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG); - - /* Set dmic out format */ - ctrl &= ~(OMAP_DMIC_FORMAT | OMAP_DMIC_POLAR_MASK); - ctrl |= (OMAP_DMICOUTFORMAT_LJUST | OMAP_DMIC_POLAR1 | - OMAP_DMIC_POLAR2 | OMAP_DMIC_POLAR3); - - /* Configure dmic clock divider */ - ctrl &= ~OMAP_DMIC_CLK_DIV_MASK; - ctrl |= OMAP_DMIC_CLK_DIV(dmic->clk_div); - - omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, ctrl); - - omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, - ctrl | OMAP_DMICOUTFORMAT_LJUST | OMAP_DMIC_POLAR1 | - OMAP_DMIC_POLAR2 | OMAP_DMIC_POLAR3); - - return 0; -} - -static int omap_dmic_dai_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) -{ - struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - omap_dmic_start(dmic); - break; - case SNDRV_PCM_TRIGGER_STOP: - omap_dmic_stop(dmic); - break; - default: - break; - } - - return 0; -} - -static int omap_dmic_select_fclk(struct omap_dmic *dmic, int clk_id, - unsigned int freq) -{ - struct clk *parent_clk, *mux; - char *parent_clk_name; - int ret = 0; - - switch (freq) { - case 12000000: - case 19200000: - case 24000000: - case 24576000: - break; - default: - dev_err(dmic->dev, "invalid input frequency: %dHz\n", freq); - dmic->fclk_freq = 0; - return -EINVAL; - } - - if (dmic->sysclk == clk_id) { - dmic->fclk_freq = freq; - return 0; - } - - /* re-parent not allowed if a stream is ongoing */ - if (dmic->active && dmic_is_enabled(dmic)) { - dev_err(dmic->dev, "can't re-parent when DMIC active\n"); - return -EBUSY; - } - - switch (clk_id) { - case OMAP_DMIC_SYSCLK_PAD_CLKS: - parent_clk_name = "pad_clks_ck"; - break; - case OMAP_DMIC_SYSCLK_SLIMBLUS_CLKS: - parent_clk_name = "slimbus_clk"; - break; - case OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS: - parent_clk_name = "dmic_sync_mux_ck"; - break; - default: - dev_err(dmic->dev, "fclk clk_id (%d) not supported\n", clk_id); - return -EINVAL; - } - - parent_clk = clk_get(dmic->dev, parent_clk_name); - if (IS_ERR(parent_clk)) { - dev_err(dmic->dev, "can't get %s\n", parent_clk_name); - return -ENODEV; - } - - mux = clk_get_parent(dmic->fclk); - if (IS_ERR(mux)) { - dev_err(dmic->dev, "can't get fck mux parent\n"); - clk_put(parent_clk); - return -ENODEV; - } - - mutex_lock(&dmic->mutex); - if (dmic->active) { - /* disable clock while reparenting */ - pm_runtime_put_sync(dmic->dev); - ret = clk_set_parent(mux, parent_clk); - pm_runtime_get_sync(dmic->dev); - } else { - ret = clk_set_parent(mux, parent_clk); - } - mutex_unlock(&dmic->mutex); - - if (ret < 0) { - dev_err(dmic->dev, "re-parent failed\n"); - goto err_busy; - } - - dmic->sysclk = clk_id; - dmic->fclk_freq = freq; - -err_busy: - clk_put(mux); - clk_put(parent_clk); - - return ret; -} - -static int omap_dmic_select_outclk(struct omap_dmic *dmic, int clk_id, - unsigned int freq) -{ - int ret = 0; - - if (clk_id != OMAP_DMIC_ABE_DMIC_CLK) { - dev_err(dmic->dev, "output clk_id (%d) not supported\n", - clk_id); - return -EINVAL; - } - - switch (freq) { - case 1536000: - case 2400000: - case 3072000: - case 3840000: - dmic->out_freq = freq; - break; - default: - dev_err(dmic->dev, "invalid out frequency: %dHz\n", freq); - dmic->out_freq = 0; - ret = -EINVAL; - } - - return ret; -} - -static int omap_dmic_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, - unsigned int freq, int dir) -{ - struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); - - if (dir == SND_SOC_CLOCK_IN) - return omap_dmic_select_fclk(dmic, clk_id, freq); - else if (dir == SND_SOC_CLOCK_OUT) - return omap_dmic_select_outclk(dmic, clk_id, freq); - - dev_err(dmic->dev, "invalid clock direction (%d)\n", dir); - return -EINVAL; -} - -static const struct snd_soc_dai_ops omap_dmic_dai_ops = { - .startup = omap_dmic_dai_startup, - .shutdown = omap_dmic_dai_shutdown, - .hw_params = omap_dmic_dai_hw_params, - .prepare = omap_dmic_dai_prepare, - .trigger = omap_dmic_dai_trigger, - .set_sysclk = omap_dmic_set_dai_sysclk, -}; - -static int omap_dmic_probe(struct snd_soc_dai *dai) -{ - struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); - - pm_runtime_enable(dmic->dev); - - /* Disable lines while request is ongoing */ - pm_runtime_get_sync(dmic->dev); - omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, 0x00); - pm_runtime_put_sync(dmic->dev); - - /* Configure DMIC threshold value */ - dmic->threshold = OMAP_DMIC_THRES_MAX - 3; - - snd_soc_dai_init_dma_data(dai, NULL, &dmic->dma_data); - - return 0; -} - -static int omap_dmic_remove(struct snd_soc_dai *dai) -{ - struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); - - pm_runtime_disable(dmic->dev); - - return 0; -} - -static struct snd_soc_dai_driver omap_dmic_dai = { - .name = "omap-dmic", - .probe = omap_dmic_probe, - .remove = omap_dmic_remove, - .capture = { - .channels_min = 2, - .channels_max = 6, - .rates = SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S32_LE, - .sig_bits = 24, - }, - .ops = &omap_dmic_dai_ops, -}; - -static const struct snd_soc_component_driver omap_dmic_component = { - .name = "omap-dmic", -}; - -static int asoc_dmic_probe(struct platform_device *pdev) -{ - struct omap_dmic *dmic; - struct resource *res; - int ret; - - dmic = devm_kzalloc(&pdev->dev, sizeof(struct omap_dmic), GFP_KERNEL); - if (!dmic) - return -ENOMEM; - - platform_set_drvdata(pdev, dmic); - dmic->dev = &pdev->dev; - dmic->sysclk = OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS; - - mutex_init(&dmic->mutex); - - dmic->fclk = devm_clk_get(dmic->dev, "fck"); - if (IS_ERR(dmic->fclk)) { - dev_err(dmic->dev, "cant get fck\n"); - return -ENODEV; - } - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); - if (!res) { - dev_err(dmic->dev, "invalid dma memory resource\n"); - return -ENODEV; - } - dmic->dma_data.addr = res->start + OMAP_DMIC_DATA_REG; - - dmic->dma_data.filter_data = "up_link"; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); - dmic->io_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(dmic->io_base)) - return PTR_ERR(dmic->io_base); - - - ret = devm_snd_soc_register_component(&pdev->dev, - &omap_dmic_component, - &omap_dmic_dai, 1); - if (ret) - return ret; - - ret = sdma_pcm_platform_register(&pdev->dev, NULL, "up_link"); - if (ret) - return ret; - - return 0; -} - -static const struct of_device_id omap_dmic_of_match[] = { - { .compatible = "ti,omap4-dmic", }, - { } -}; -MODULE_DEVICE_TABLE(of, omap_dmic_of_match); - -static struct platform_driver asoc_dmic_driver = { - .driver = { - .name = "omap-dmic", - .of_match_table = omap_dmic_of_match, - }, - .probe = asoc_dmic_probe, -}; - -module_platform_driver(asoc_dmic_driver); - -MODULE_ALIAS("platform:omap-dmic"); -MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); -MODULE_DESCRIPTION("OMAP DMIC ASoC Interface"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap-dmic.h b/sound/soc/omap/omap-dmic.h deleted file mode 100644 index 231e728bff0e..000000000000 --- a/sound/soc/omap/omap-dmic.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * omap-dmic.h -- OMAP Digital Microphone Controller - * - * 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. - */ - -#ifndef _OMAP_DMIC_H -#define _OMAP_DMIC_H - -#define OMAP_DMIC_REVISION_REG 0x00 -#define OMAP_DMIC_SYSCONFIG_REG 0x10 -#define OMAP_DMIC_IRQSTATUS_RAW_REG 0x24 -#define OMAP_DMIC_IRQSTATUS_REG 0x28 -#define OMAP_DMIC_IRQENABLE_SET_REG 0x2C -#define OMAP_DMIC_IRQENABLE_CLR_REG 0x30 -#define OMAP_DMIC_IRQWAKE_EN_REG 0x34 -#define OMAP_DMIC_DMAENABLE_SET_REG 0x38 -#define OMAP_DMIC_DMAENABLE_CLR_REG 0x3C -#define OMAP_DMIC_DMAWAKEEN_REG 0x40 -#define OMAP_DMIC_CTRL_REG 0x44 -#define OMAP_DMIC_DATA_REG 0x48 -#define OMAP_DMIC_FIFO_CTRL_REG 0x4C -#define OMAP_DMIC_FIFO_DMIC1R_DATA_REG 0x50 -#define OMAP_DMIC_FIFO_DMIC1L_DATA_REG 0x54 -#define OMAP_DMIC_FIFO_DMIC2R_DATA_REG 0x58 -#define OMAP_DMIC_FIFO_DMIC2L_DATA_REG 0x5C -#define OMAP_DMIC_FIFO_DMIC3R_DATA_REG 0x60 -#define OMAP_DMIC_FIFO_DMIC3L_DATA_REG 0x64 - -/* IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR bit fields */ -#define OMAP_DMIC_IRQ (1 << 0) -#define OMAP_DMIC_IRQ_FULL (1 << 1) -#define OMAP_DMIC_IRQ_ALMST_EMPTY (1 << 2) -#define OMAP_DMIC_IRQ_EMPTY (1 << 3) -#define OMAP_DMIC_IRQ_MASK 0x07 - -/* DMIC_DMAENABLE bit fields */ -#define OMAP_DMIC_DMA_ENABLE 0x1 - -/* DMIC_CTRL bit fields */ -#define OMAP_DMIC_UP1_ENABLE (1 << 0) -#define OMAP_DMIC_UP2_ENABLE (1 << 1) -#define OMAP_DMIC_UP3_ENABLE (1 << 2) -#define OMAP_DMIC_UP_ENABLE_MASK 0x7 -#define OMAP_DMIC_FORMAT (1 << 3) -#define OMAP_DMIC_POLAR1 (1 << 4) -#define OMAP_DMIC_POLAR2 (1 << 5) -#define OMAP_DMIC_POLAR3 (1 << 6) -#define OMAP_DMIC_POLAR_MASK (0x7 << 4) -#define OMAP_DMIC_CLK_DIV(x) (((x) & 0x7) << 7) -#define OMAP_DMIC_CLK_DIV_MASK (0x7 << 7) -#define OMAP_DMIC_RESET (1 << 10) - -#define OMAP_DMICOUTFORMAT_LJUST (0 << 3) -#define OMAP_DMICOUTFORMAT_RJUST (1 << 3) - -/* DMIC_FIFO_CTRL bit fields */ -#define OMAP_DMIC_THRES_MAX 0xF - -enum omap_dmic_clk { - OMAP_DMIC_SYSCLK_PAD_CLKS, /* PAD_CLKS */ - OMAP_DMIC_SYSCLK_SLIMBLUS_CLKS, /* SLIMBUS_CLK */ - OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS, /* DMIC_SYNC_MUX_CLK */ - OMAP_DMIC_ABE_DMIC_CLK, /* abe_dmic_clk */ -}; - -#endif diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c deleted file mode 100644 index 673a9eb153b2..000000000000 --- a/sound/soc/omap/omap-hdmi-audio.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * omap-hdmi-audio.c -- OMAP4+ DSS HDMI audio support library - * - * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com - * - * Author: Jyri Sarha <jsarha@ti.com> - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/err.h> -#include <linux/string.h> -#include <linux/platform_device.h> -#include <sound/soc.h> -#include <sound/pcm_params.h> -#include <sound/dmaengine_pcm.h> -#include <uapi/sound/asound.h> -#include <sound/asoundef.h> -#include <sound/omap-hdmi-audio.h> - -#include "sdma-pcm.h" - -#define DRV_NAME "omap-hdmi-audio" - -struct hdmi_audio_data { - struct snd_soc_card *card; - - const struct omap_hdmi_audio_ops *ops; - struct device *dssdev; - struct snd_dmaengine_dai_dma_data dma_data; - struct omap_dss_audio dss_audio; - struct snd_aes_iec958 iec; - struct snd_cea_861_aud_if cea; - - struct mutex current_stream_lock; - struct snd_pcm_substream *current_stream; -}; - -static -struct hdmi_audio_data *card_drvdata_substream(struct snd_pcm_substream *ss) -{ - struct snd_soc_pcm_runtime *rtd = ss->private_data; - - return snd_soc_card_get_drvdata(rtd->card); -} - -static void hdmi_dai_abort(struct device *dev) -{ - struct hdmi_audio_data *ad = dev_get_drvdata(dev); - - mutex_lock(&ad->current_stream_lock); - if (ad->current_stream && ad->current_stream->runtime && - snd_pcm_running(ad->current_stream)) { - dev_err(dev, "HDMI display disabled, aborting playback\n"); - snd_pcm_stream_lock_irq(ad->current_stream); - snd_pcm_stop(ad->current_stream, SNDRV_PCM_STATE_DISCONNECTED); - snd_pcm_stream_unlock_irq(ad->current_stream); - } - mutex_unlock(&ad->current_stream_lock); -} - -static int hdmi_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct hdmi_audio_data *ad = card_drvdata_substream(substream); - int ret; - /* - * Make sure that the period bytes are multiple of the DMA packet size. - * Largest packet size we use is 32 32-bit words = 128 bytes - */ - ret = snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); - if (ret < 0) { - dev_err(dai->dev, "Could not apply period constraint: %d\n", - ret); - return ret; - } - ret = snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128); - if (ret < 0) { - dev_err(dai->dev, "Could not apply buffer constraint: %d\n", - ret); - return ret; - } - - snd_soc_dai_set_dma_data(dai, substream, &ad->dma_data); - - mutex_lock(&ad->current_stream_lock); - ad->current_stream = substream; - mutex_unlock(&ad->current_stream_lock); - - ret = ad->ops->audio_startup(ad->dssdev, hdmi_dai_abort); - - if (ret) { - mutex_lock(&ad->current_stream_lock); - ad->current_stream = NULL; - mutex_unlock(&ad->current_stream_lock); - } - - return ret; -} - -static int hdmi_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct hdmi_audio_data *ad = card_drvdata_substream(substream); - struct snd_aes_iec958 *iec = &ad->iec; - struct snd_cea_861_aud_if *cea = &ad->cea; - - WARN_ON(ad->current_stream != substream); - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - ad->dma_data.maxburst = 16; - break; - case SNDRV_PCM_FORMAT_S24_LE: - ad->dma_data.maxburst = 32; - break; - default: - dev_err(dai->dev, "format not supported!\n"); - return -EINVAL; - } - - ad->dss_audio.iec = iec; - ad->dss_audio.cea = cea; - /* - * fill the IEC-60958 channel status word - */ - /* initialize the word bytes */ - memset(iec->status, 0, sizeof(iec->status)); - - /* specify IEC-60958-3 (commercial use) */ - iec->status[0] &= ~IEC958_AES0_PROFESSIONAL; - - /* specify that the audio is LPCM*/ - iec->status[0] &= ~IEC958_AES0_NONAUDIO; - - iec->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT; - - iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE; - - iec->status[1] = IEC958_AES1_CON_GENERAL; - - iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC; - - iec->status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC; - - switch (params_rate(params)) { - case 32000: - iec->status[3] |= IEC958_AES3_CON_FS_32000; - break; - case 44100: - iec->status[3] |= IEC958_AES3_CON_FS_44100; - break; - case 48000: - iec->status[3] |= IEC958_AES3_CON_FS_48000; - break; - case 88200: - iec->status[3] |= IEC958_AES3_CON_FS_88200; - break; - case 96000: - iec->status[3] |= IEC958_AES3_CON_FS_96000; - break; - case 176400: - iec->status[3] |= IEC958_AES3_CON_FS_176400; - break; - case 192000: - iec->status[3] |= IEC958_AES3_CON_FS_192000; - break; - default: - dev_err(dai->dev, "rate not supported!\n"); - return -EINVAL; - } - - /* specify the clock accuracy */ - iec->status[3] |= IEC958_AES3_CON_CLOCK_1000PPM; - - /* - * specify the word length. The same word length value can mean - * two different lengths. Hence, we need to specify the maximum - * word length as well. - */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - iec->status[4] |= IEC958_AES4_CON_WORDLEN_20_16; - iec->status[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24; - break; - case SNDRV_PCM_FORMAT_S24_LE: - iec->status[4] |= IEC958_AES4_CON_WORDLEN_24_20; - iec->status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24; - break; - default: - dev_err(dai->dev, "format not supported!\n"); - return -EINVAL; - } - - /* - * Fill the CEA-861 audio infoframe (see spec for details) - */ - - cea->db1_ct_cc = (params_channels(params) - 1) - & CEA861_AUDIO_INFOFRAME_DB1CC; - cea->db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM; - - cea->db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM; - cea->db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM; - - cea->db3 = 0; /* not used, all zeros */ - - if (params_channels(params) == 2) - cea->db4_ca = 0x0; - else if (params_channels(params) == 6) - cea->db4_ca = 0xb; - else - cea->db4_ca = 0x13; - - if (cea->db4_ca == 0x00) - cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PERMITTED; - else - cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED; - - /* the expression is trivial but makes clear what we are doing */ - cea->db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV); - - return ad->ops->audio_config(ad->dssdev, &ad->dss_audio); -} - -static int hdmi_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct hdmi_audio_data *ad = card_drvdata_substream(substream); - int err = 0; - - WARN_ON(ad->current_stream != substream); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - err = ad->ops->audio_start(ad->dssdev); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ad->ops->audio_stop(ad->dssdev); - break; - default: - err = -EINVAL; - } - return err; -} - -static void hdmi_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct hdmi_audio_data *ad = card_drvdata_substream(substream); - - WARN_ON(ad->current_stream != substream); - - ad->ops->audio_shutdown(ad->dssdev); - - mutex_lock(&ad->current_stream_lock); - ad->current_stream = NULL; - mutex_unlock(&ad->current_stream_lock); -} - -static const struct snd_soc_dai_ops hdmi_dai_ops = { - .startup = hdmi_dai_startup, - .hw_params = hdmi_dai_hw_params, - .trigger = hdmi_dai_trigger, - .shutdown = hdmi_dai_shutdown, -}; - -static const struct snd_soc_component_driver omap_hdmi_component = { - .name = "omapdss_hdmi", -}; - -static struct snd_soc_dai_driver omap5_hdmi_dai = { - .name = "omap5-hdmi-dai", - .playback = { - .channels_min = 2, - .channels_max = 8, - .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | - SNDRV_PCM_RATE_192000), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .ops = &hdmi_dai_ops, -}; - -static struct snd_soc_dai_driver omap4_hdmi_dai = { - .name = "omap4-hdmi-dai", - .playback = { - .channels_min = 2, - .channels_max = 8, - .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | - SNDRV_PCM_RATE_192000), - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - }, - .ops = &hdmi_dai_ops, -}; - -static int omap_hdmi_audio_probe(struct platform_device *pdev) -{ - struct omap_hdmi_audio_pdata *ha = pdev->dev.platform_data; - struct device *dev = &pdev->dev; - struct hdmi_audio_data *ad; - struct snd_soc_dai_driver *dai_drv; - struct snd_soc_card *card; - int ret; - - if (!ha) { - dev_err(dev, "No platform data\n"); - return -EINVAL; - } - - ad = devm_kzalloc(dev, sizeof(*ad), GFP_KERNEL); - if (!ad) - return -ENOMEM; - ad->dssdev = ha->dev; - ad->ops = ha->ops; - ad->dma_data.addr = ha->audio_dma_addr; - ad->dma_data.filter_data = "audio_tx"; - ad->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - mutex_init(&ad->current_stream_lock); - - switch (ha->version) { - case 4: - dai_drv = &omap4_hdmi_dai; - break; - case 5: - dai_drv = &omap5_hdmi_dai; - break; - default: - return -EINVAL; - } - ret = devm_snd_soc_register_component(ad->dssdev, &omap_hdmi_component, - dai_drv, 1); - if (ret) - return ret; - - ret = sdma_pcm_platform_register(ad->dssdev, "audio_tx", NULL); - if (ret) - return ret; - - card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); - if (!card) - return -ENOMEM; - - card->name = devm_kasprintf(dev, GFP_KERNEL, - "HDMI %s", dev_name(ad->dssdev)); - if (!card->name) - return -ENOMEM; - - card->owner = THIS_MODULE; - card->dai_link = - devm_kzalloc(dev, sizeof(*(card->dai_link)), GFP_KERNEL); - if (!card->dai_link) - return -ENOMEM; - card->dai_link->name = card->name; - card->dai_link->stream_name = card->name; - card->dai_link->cpu_dai_name = dev_name(ad->dssdev); - card->dai_link->platform_name = dev_name(ad->dssdev); - card->dai_link->codec_name = "snd-soc-dummy"; - card->dai_link->codec_dai_name = "snd-soc-dummy-dai"; - card->num_links = 1; - card->dev = dev; - - ret = snd_soc_register_card(card); - if (ret) { - dev_err(dev, "snd_soc_register_card failed (%d)\n", ret); - return ret; - } - - ad->card = card; - snd_soc_card_set_drvdata(card, ad); - - dev_set_drvdata(dev, ad); - - return 0; -} - -static int omap_hdmi_audio_remove(struct platform_device *pdev) -{ - struct hdmi_audio_data *ad = platform_get_drvdata(pdev); - - snd_soc_unregister_card(ad->card); - return 0; -} - -static struct platform_driver hdmi_audio_driver = { - .driver = { - .name = DRV_NAME, - }, - .probe = omap_hdmi_audio_probe, - .remove = omap_hdmi_audio_remove, -}; - -module_platform_driver(hdmi_audio_driver); - -MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>"); -MODULE_DESCRIPTION("OMAP HDMI Audio Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/omap/omap-mcbsp-priv.h b/sound/soc/omap/omap-mcbsp-priv.h deleted file mode 100644 index 7865cda4bf0a..000000000000 --- a/sound/soc/omap/omap-mcbsp-priv.h +++ /dev/null @@ -1,324 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * OMAP Multi-Channel Buffered Serial Port - * - * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> - * Peter Ujfalusi <peter.ujfalusi@ti.com> - */ - -#ifndef __OMAP_MCBSP_PRIV_H__ -#define __OMAP_MCBSP_PRIV_H__ - -#include <linux/platform_data/asoc-ti-mcbsp.h> - -#ifdef CONFIG_ARCH_OMAP1 -#define mcbsp_omap1() 1 -#else -#define mcbsp_omap1() 0 -#endif - -/* McBSP register numbers. Register address offset = num * reg_step */ -enum { - /* Common registers */ - OMAP_MCBSP_REG_SPCR2 = 4, - OMAP_MCBSP_REG_SPCR1, - OMAP_MCBSP_REG_RCR2, - OMAP_MCBSP_REG_RCR1, - OMAP_MCBSP_REG_XCR2, - OMAP_MCBSP_REG_XCR1, - OMAP_MCBSP_REG_SRGR2, - OMAP_MCBSP_REG_SRGR1, - OMAP_MCBSP_REG_MCR2, - OMAP_MCBSP_REG_MCR1, - OMAP_MCBSP_REG_RCERA, - OMAP_MCBSP_REG_RCERB, - OMAP_MCBSP_REG_XCERA, - OMAP_MCBSP_REG_XCERB, - OMAP_MCBSP_REG_PCR0, - OMAP_MCBSP_REG_RCERC, - OMAP_MCBSP_REG_RCERD, - OMAP_MCBSP_REG_XCERC, - OMAP_MCBSP_REG_XCERD, - OMAP_MCBSP_REG_RCERE, - OMAP_MCBSP_REG_RCERF, - OMAP_MCBSP_REG_XCERE, - OMAP_MCBSP_REG_XCERF, - OMAP_MCBSP_REG_RCERG, - OMAP_MCBSP_REG_RCERH, - OMAP_MCBSP_REG_XCERG, - OMAP_MCBSP_REG_XCERH, - - /* OMAP1-OMAP2420 registers */ - OMAP_MCBSP_REG_DRR2 = 0, - OMAP_MCBSP_REG_DRR1, - OMAP_MCBSP_REG_DXR2, - OMAP_MCBSP_REG_DXR1, - - /* OMAP2430 and onwards */ - OMAP_MCBSP_REG_DRR = 0, - OMAP_MCBSP_REG_DXR = 2, - OMAP_MCBSP_REG_SYSCON = 35, - OMAP_MCBSP_REG_THRSH2, - OMAP_MCBSP_REG_THRSH1, - OMAP_MCBSP_REG_IRQST = 40, - OMAP_MCBSP_REG_IRQEN, - OMAP_MCBSP_REG_WAKEUPEN, - OMAP_MCBSP_REG_XCCR, - OMAP_MCBSP_REG_RCCR, - OMAP_MCBSP_REG_XBUFFSTAT, - OMAP_MCBSP_REG_RBUFFSTAT, - OMAP_MCBSP_REG_SSELCR, -}; - -/************************** McBSP SPCR1 bit definitions ***********************/ -#define RRST BIT(0) -#define RRDY BIT(1) -#define RFULL BIT(2) -#define RSYNC_ERR BIT(3) -#define RINTM(value) (((value) & 0x3) << 4) /* bits 4:5 */ -#define ABIS BIT(6) -#define DXENA BIT(7) -#define CLKSTP(value) (((value) & 0x3) << 11) /* bits 11:12 */ -#define RJUST(value) (((value) & 0x3) << 13) /* bits 13:14 */ -#define ALB BIT(15) -#define DLB BIT(15) - -/************************** McBSP SPCR2 bit definitions ***********************/ -#define XRST BIT(0) -#define XRDY BIT(1) -#define XEMPTY BIT(2) -#define XSYNC_ERR BIT(3) -#define XINTM(value) (((value) & 0x3) << 4) /* bits 4:5 */ -#define GRST BIT(6) -#define FRST BIT(7) -#define SOFT BIT(8) -#define FREE BIT(9) - -/************************** McBSP PCR bit definitions *************************/ -#define CLKRP BIT(0) -#define CLKXP BIT(1) -#define FSRP BIT(2) -#define FSXP BIT(3) -#define DR_STAT BIT(4) -#define DX_STAT BIT(5) -#define CLKS_STAT BIT(6) -#define SCLKME BIT(7) -#define CLKRM BIT(8) -#define CLKXM BIT(9) -#define FSRM BIT(10) -#define FSXM BIT(11) -#define RIOEN BIT(12) -#define XIOEN BIT(13) -#define IDLE_EN BIT(14) - -/************************** McBSP RCR1 bit definitions ************************/ -#define RWDLEN1(value) (((value) & 0x7) << 5) /* Bits 5:7 */ -#define RFRLEN1(value) (((value) & 0x7f) << 8) /* Bits 8:14 */ - -/************************** McBSP XCR1 bit definitions ************************/ -#define XWDLEN1(value) (((value) & 0x7) << 5) /* Bits 5:7 */ -#define XFRLEN1(value) (((value) & 0x7f) << 8) /* Bits 8:14 */ - -/*************************** McBSP RCR2 bit definitions ***********************/ -#define RDATDLY(value) ((value) & 0x3) /* Bits 0:1 */ -#define RFIG BIT(2) -#define RCOMPAND(value) (((value) & 0x3) << 3) /* Bits 3:4 */ -#define RWDLEN2(value) (((value) & 0x7) << 5) /* Bits 5:7 */ -#define RFRLEN2(value) (((value) & 0x7f) << 8) /* Bits 8:14 */ -#define RPHASE BIT(15) - -/*************************** McBSP XCR2 bit definitions ***********************/ -#define XDATDLY(value) ((value) & 0x3) /* Bits 0:1 */ -#define XFIG BIT(2) -#define XCOMPAND(value) (((value) & 0x3) << 3) /* Bits 3:4 */ -#define XWDLEN2(value) (((value) & 0x7) << 5) /* Bits 5:7 */ -#define XFRLEN2(value) (((value) & 0x7f) << 8) /* Bits 8:14 */ -#define XPHASE BIT(15) - -/************************* McBSP SRGR1 bit definitions ************************/ -#define CLKGDV(value) ((value) & 0x7f) /* Bits 0:7 */ -#define FWID(value) (((value) & 0xff) << 8) /* Bits 8:15 */ - -/************************* McBSP SRGR2 bit definitions ************************/ -#define FPER(value) ((value) & 0x0fff) /* Bits 0:11 */ -#define FSGM BIT(12) -#define CLKSM BIT(13) -#define CLKSP BIT(14) -#define GSYNC BIT(15) - -/************************* McBSP MCR1 bit definitions *************************/ -#define RMCM BIT(0) -#define RCBLK(value) (((value) & 0x7) << 2) /* Bits 2:4 */ -#define RPABLK(value) (((value) & 0x3) << 5) /* Bits 5:6 */ -#define RPBBLK(value) (((value) & 0x3) << 7) /* Bits 7:8 */ - -/************************* McBSP MCR2 bit definitions *************************/ -#define XMCM(value) ((value) & 0x3) /* Bits 0:1 */ -#define XCBLK(value) (((value) & 0x7) << 2) /* Bits 2:4 */ -#define XPABLK(value) (((value) & 0x3) << 5) /* Bits 5:6 */ -#define XPBBLK(value) (((value) & 0x3) << 7) /* Bits 7:8 */ - -/*********************** McBSP XCCR bit definitions *************************/ -#define XDISABLE BIT(0) -#define XDMAEN BIT(3) -#define DILB BIT(5) -#define XFULL_CYCLE BIT(11) -#define DXENDLY(value) (((value) & 0x3) << 12) /* Bits 12:13 */ -#define PPCONNECT BIT(14) -#define EXTCLKGATE BIT(15) - -/********************** McBSP RCCR bit definitions *************************/ -#define RDISABLE BIT(0) -#define RDMAEN BIT(3) -#define RFULL_CYCLE BIT(11) - -/********************** McBSP SYSCONFIG bit definitions ********************/ -#define SOFTRST BIT(1) -#define ENAWAKEUP BIT(2) -#define SIDLEMODE(value) (((value) & 0x3) << 3) -#define CLOCKACTIVITY(value) (((value) & 0x3) << 8) - -/********************** McBSP DMA operating modes **************************/ -#define MCBSP_DMA_MODE_ELEMENT 0 -#define MCBSP_DMA_MODE_THRESHOLD 1 - -/********************** McBSP WAKEUPEN/IRQST/IRQEN bit definitions *********/ -#define RSYNCERREN BIT(0) -#define RFSREN BIT(1) -#define REOFEN BIT(2) -#define RRDYEN BIT(3) -#define RUNDFLEN BIT(4) -#define ROVFLEN BIT(5) -#define XSYNCERREN BIT(7) -#define XFSXEN BIT(8) -#define XEOFEN BIT(9) -#define XRDYEN BIT(10) -#define XUNDFLEN BIT(11) -#define XOVFLEN BIT(12) -#define XEMPTYEOFEN BIT(14) - -/* Clock signal muxing options */ -#define CLKR_SRC_CLKR 0 /* CLKR signal is from the CLKR pin */ -#define CLKR_SRC_CLKX 1 /* CLKR signal is from the CLKX pin */ -#define FSR_SRC_FSR 2 /* FSR signal is from the FSR pin */ -#define FSR_SRC_FSX 3 /* FSR signal is from the FSX pin */ - -/* McBSP functional clock sources */ -#define MCBSP_CLKS_PRCM_SRC 0 -#define MCBSP_CLKS_PAD_SRC 1 - -/* we don't do multichannel for now */ -struct omap_mcbsp_reg_cfg { - u16 spcr2; - u16 spcr1; - u16 rcr2; - u16 rcr1; - u16 xcr2; - u16 xcr1; - u16 srgr2; - u16 srgr1; - u16 mcr2; - u16 mcr1; - u16 pcr0; - u16 rcerc; - u16 rcerd; - u16 xcerc; - u16 xcerd; - u16 rcere; - u16 rcerf; - u16 xcere; - u16 xcerf; - u16 rcerg; - u16 rcerh; - u16 xcerg; - u16 xcerh; - u16 xccr; - u16 rccr; -}; - -struct omap_mcbsp_st_data; - -struct omap_mcbsp { - struct device *dev; - struct clk *fclk; - spinlock_t lock; - unsigned long phys_base; - unsigned long phys_dma_base; - void __iomem *io_base; - u8 id; - /* - * Flags indicating is the bus already activated and configured by - * another substream - */ - int active; - int configured; - u8 free; - - int irq; - int rx_irq; - int tx_irq; - - /* Protect the field .free, while checking if the mcbsp is in use */ - struct omap_mcbsp_platform_data *pdata; - struct omap_mcbsp_st_data *st_data; - struct omap_mcbsp_reg_cfg cfg_regs; - struct snd_dmaengine_dai_dma_data dma_data[2]; - unsigned int dma_req[2]; - int dma_op_mode; - u16 max_tx_thres; - u16 max_rx_thres; - void *reg_cache; - int reg_cache_size; - - unsigned int fmt; - unsigned int in_freq; - unsigned int latency[2]; - int clk_div; - int wlen; - - struct pm_qos_request pm_qos_req; -}; - -static inline void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) -{ - void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step; - - if (mcbsp->pdata->reg_size == 2) { - ((u16 *)mcbsp->reg_cache)[reg] = (u16)val; - writew_relaxed((u16)val, addr); - } else { - ((u32 *)mcbsp->reg_cache)[reg] = val; - writel_relaxed(val, addr); - } -} - -static inline int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, - bool from_cache) -{ - void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step; - - if (mcbsp->pdata->reg_size == 2) { - return !from_cache ? readw_relaxed(addr) : - ((u16 *)mcbsp->reg_cache)[reg]; - } else { - return !from_cache ? readl_relaxed(addr) : - ((u32 *)mcbsp->reg_cache)[reg]; - } -} - -#define MCBSP_READ(mcbsp, reg) \ - omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0) -#define MCBSP_WRITE(mcbsp, reg, val) \ - omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val) -#define MCBSP_READ_CACHE(mcbsp, reg) \ - omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1) - - -/* Sidetone specific API */ -int omap_mcbsp_st_init(struct platform_device *pdev); -void omap_mcbsp_st_cleanup(struct platform_device *pdev); - -int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp); -int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp); - -#endif /* __OMAP_MCBSP_PRIV_H__ */ diff --git a/sound/soc/omap/omap-mcbsp-st.c b/sound/soc/omap/omap-mcbsp-st.c deleted file mode 100644 index 1a3fe854e856..000000000000 --- a/sound/soc/omap/omap-mcbsp-st.c +++ /dev/null @@ -1,516 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * McBSP Sidetone support - * - * Copyright (C) 2004 Nokia Corporation - * Author: Samuel Ortiz <samuel.ortiz@nokia.com> - * - * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> - * Peter Ujfalusi <peter.ujfalusi@ti.com> - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/device.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/pm_runtime.h> - -#include "omap-mcbsp.h" -#include "omap-mcbsp-priv.h" - -/* OMAP3 sidetone control registers */ -#define OMAP_ST_REG_REV 0x00 -#define OMAP_ST_REG_SYSCONFIG 0x10 -#define OMAP_ST_REG_IRQSTATUS 0x18 -#define OMAP_ST_REG_IRQENABLE 0x1C -#define OMAP_ST_REG_SGAINCR 0x24 -#define OMAP_ST_REG_SFIRCR 0x28 -#define OMAP_ST_REG_SSELCR 0x2C - -/********************** McBSP SSELCR bit definitions ***********************/ -#define SIDETONEEN BIT(10) - -/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/ -#define ST_AUTOIDLE BIT(0) - -/********************** McBSP Sidetone SGAINCR bit definitions *************/ -#define ST_CH0GAIN(value) ((value) & 0xffff) /* Bits 0:15 */ -#define ST_CH1GAIN(value) (((value) & 0xffff) << 16) /* Bits 16:31 */ - -/********************** McBSP Sidetone SFIRCR bit definitions **************/ -#define ST_FIRCOEFF(value) ((value) & 0xffff) /* Bits 0:15 */ - -/********************** McBSP Sidetone SSELCR bit definitions **************/ -#define ST_SIDETONEEN BIT(0) -#define ST_COEFFWREN BIT(1) -#define ST_COEFFWRDONE BIT(2) - -struct omap_mcbsp_st_data { - void __iomem *io_base_st; - struct clk *mcbsp_iclk; - bool running; - bool enabled; - s16 taps[128]; /* Sidetone filter coefficients */ - int nr_taps; /* Number of filter coefficients in use */ - s16 ch0gain; - s16 ch1gain; -}; - -static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) -{ - writel_relaxed(val, mcbsp->st_data->io_base_st + reg); -} - -static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg) -{ - return readl_relaxed(mcbsp->st_data->io_base_st + reg); -} - -#define MCBSP_ST_READ(mcbsp, reg) omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg) -#define MCBSP_ST_WRITE(mcbsp, reg, val) \ - omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val) - -static void omap_mcbsp_st_on(struct omap_mcbsp *mcbsp) -{ - unsigned int w; - - if (mcbsp->pdata->force_ick_on) - mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, true); - - /* Disable Sidetone clock auto-gating for normal operation */ - w = MCBSP_ST_READ(mcbsp, SYSCONFIG); - MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE)); - - /* Enable McBSP Sidetone */ - w = MCBSP_READ(mcbsp, SSELCR); - MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN); - - /* Enable Sidetone from Sidetone Core */ - w = MCBSP_ST_READ(mcbsp, SSELCR); - MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN); -} - -static void omap_mcbsp_st_off(struct omap_mcbsp *mcbsp) -{ - unsigned int w; - - w = MCBSP_ST_READ(mcbsp, SSELCR); - MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN)); - - w = MCBSP_READ(mcbsp, SSELCR); - MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN)); - - /* Enable Sidetone clock auto-gating to reduce power consumption */ - w = MCBSP_ST_READ(mcbsp, SYSCONFIG); - MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE); - - if (mcbsp->pdata->force_ick_on) - mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, false); -} - -static void omap_mcbsp_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir) -{ - u16 val, i; - - val = MCBSP_ST_READ(mcbsp, SSELCR); - - if (val & ST_COEFFWREN) - MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN)); - - MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN); - - for (i = 0; i < 128; i++) - MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]); - - i = 0; - - val = MCBSP_ST_READ(mcbsp, SSELCR); - while (!(val & ST_COEFFWRDONE) && (++i < 1000)) - val = MCBSP_ST_READ(mcbsp, SSELCR); - - MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN)); - - if (i == 1000) - dev_err(mcbsp->dev, "McBSP FIR load error!\n"); -} - -static void omap_mcbsp_st_chgain(struct omap_mcbsp *mcbsp) -{ - u16 w; - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - - w = MCBSP_ST_READ(mcbsp, SSELCR); - - MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | - ST_CH1GAIN(st_data->ch1gain)); -} - -static int omap_mcbsp_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, - s16 chgain) -{ - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - int ret = 0; - - if (!st_data) - return -ENOENT; - - spin_lock_irq(&mcbsp->lock); - if (channel == 0) - st_data->ch0gain = chgain; - else if (channel == 1) - st_data->ch1gain = chgain; - else - ret = -EINVAL; - - if (st_data->enabled) - omap_mcbsp_st_chgain(mcbsp); - spin_unlock_irq(&mcbsp->lock); - - return ret; -} - -static int omap_mcbsp_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, - s16 *chgain) -{ - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - int ret = 0; - - if (!st_data) - return -ENOENT; - - spin_lock_irq(&mcbsp->lock); - if (channel == 0) - *chgain = st_data->ch0gain; - else if (channel == 1) - *chgain = st_data->ch1gain; - else - ret = -EINVAL; - spin_unlock_irq(&mcbsp->lock); - - return ret; -} - -static int omap_mcbsp_st_enable(struct omap_mcbsp *mcbsp) -{ - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - - if (!st_data) - return -ENODEV; - - spin_lock_irq(&mcbsp->lock); - st_data->enabled = 1; - omap_mcbsp_st_start(mcbsp); - spin_unlock_irq(&mcbsp->lock); - - return 0; -} - -static int omap_mcbsp_st_disable(struct omap_mcbsp *mcbsp) -{ - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - int ret = 0; - - if (!st_data) - return -ENODEV; - - spin_lock_irq(&mcbsp->lock); - omap_mcbsp_st_stop(mcbsp); - st_data->enabled = 0; - spin_unlock_irq(&mcbsp->lock); - - return ret; -} - -static int omap_mcbsp_st_is_enabled(struct omap_mcbsp *mcbsp) -{ - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - - if (!st_data) - return -ENODEV; - - return st_data->enabled; -} - -static ssize_t st_taps_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - ssize_t status = 0; - int i; - - spin_lock_irq(&mcbsp->lock); - for (i = 0; i < st_data->nr_taps; i++) - status += sprintf(&buf[status], (i ? ", %d" : "%d"), - st_data->taps[i]); - if (i) - status += sprintf(&buf[status], "\n"); - spin_unlock_irq(&mcbsp->lock); - - return status; -} - -static ssize_t st_taps_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - int val, tmp, status, i = 0; - - spin_lock_irq(&mcbsp->lock); - memset(st_data->taps, 0, sizeof(st_data->taps)); - st_data->nr_taps = 0; - - do { - status = sscanf(buf, "%d%n", &val, &tmp); - if (status < 0 || status == 0) { - size = -EINVAL; - goto out; - } - if (val < -32768 || val > 32767) { - size = -EINVAL; - goto out; - } - st_data->taps[i++] = val; - buf += tmp; - if (*buf != ',') - break; - buf++; - } while (1); - - st_data->nr_taps = i; - -out: - spin_unlock_irq(&mcbsp->lock); - - return size; -} - -static DEVICE_ATTR_RW(st_taps); - -static const struct attribute *sidetone_attrs[] = { - &dev_attr_st_taps.attr, - NULL, -}; - -static const struct attribute_group sidetone_attr_group = { - .attrs = (struct attribute **)sidetone_attrs, -}; - -int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp) -{ - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - - if (st_data->enabled && !st_data->running) { - omap_mcbsp_st_fir_write(mcbsp, st_data->taps); - omap_mcbsp_st_chgain(mcbsp); - - if (!mcbsp->free) { - omap_mcbsp_st_on(mcbsp); - st_data->running = 1; - } - } - - return 0; -} - -int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp) -{ - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - - if (st_data->running) { - if (!mcbsp->free) { - omap_mcbsp_st_off(mcbsp); - st_data->running = 0; - } - } - - return 0; -} - -int omap_mcbsp_st_init(struct platform_device *pdev) -{ - struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); - struct omap_mcbsp_st_data *st_data; - struct resource *res; - int ret; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone"); - if (!res) - return 0; - - st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL); - if (!st_data) - return -ENOMEM; - - st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick"); - if (IS_ERR(st_data->mcbsp_iclk)) { - dev_warn(mcbsp->dev, - "Failed to get ick, sidetone might be broken\n"); - st_data->mcbsp_iclk = NULL; - } - - st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start, - resource_size(res)); - if (!st_data->io_base_st) - return -ENOMEM; - - ret = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group); - if (ret) - return ret; - - mcbsp->st_data = st_data; - - return 0; -} - -void omap_mcbsp_st_cleanup(struct platform_device *pdev) -{ - struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); - - if (mcbsp->st_data) { - sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group); - clk_put(mcbsp->st_data->mcbsp_iclk); - } -} - -static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - int max = mc->max; - int min = mc->min; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = min; - uinfo->value.integer.max = max; - return 0; -} - -#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel) \ -static int \ -omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \ - struct snd_ctl_elem_value *uc) \ -{ \ - struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \ - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \ - struct soc_mixer_control *mc = \ - (struct soc_mixer_control *)kc->private_value; \ - int max = mc->max; \ - int min = mc->min; \ - int val = uc->value.integer.value[0]; \ - \ - if (val < min || val > max) \ - return -EINVAL; \ - \ - /* OMAP McBSP implementation uses index values 0..4 */ \ - return omap_mcbsp_st_set_chgain(mcbsp, channel, val); \ -} \ - \ -static int \ -omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \ - struct snd_ctl_elem_value *uc) \ -{ \ - struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \ - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \ - s16 chgain; \ - \ - if (omap_mcbsp_st_get_chgain(mcbsp, channel, &chgain)) \ - return -EAGAIN; \ - \ - uc->value.integer.value[0] = chgain; \ - return 0; \ -} - -OMAP_MCBSP_ST_CHANNEL_VOLUME(0) -OMAP_MCBSP_ST_CHANNEL_VOLUME(1) - -static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - u8 value = ucontrol->value.integer.value[0]; - - if (value == omap_mcbsp_st_is_enabled(mcbsp)) - return 0; - - if (value) - omap_mcbsp_st_enable(mcbsp); - else - omap_mcbsp_st_disable(mcbsp); - - return 1; -} - -static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - - ucontrol->value.integer.value[0] = omap_mcbsp_st_is_enabled(mcbsp); - return 0; -} - -#define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \ - xhandler_get, xhandler_put) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .info = omap_mcbsp_st_info_volsw, \ - .get = xhandler_get, .put = xhandler_put, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.min = xmin, .max = xmax} } - -#define OMAP_MCBSP_ST_CONTROLS(port) \ -static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \ -SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0, \ - omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), \ -OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \ - -32768, 32767, \ - omap_mcbsp_get_st_ch0_volume, \ - omap_mcbsp_set_st_ch0_volume), \ -OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \ - -32768, 32767, \ - omap_mcbsp_get_st_ch1_volume, \ - omap_mcbsp_set_st_ch1_volume), \ -} - -OMAP_MCBSP_ST_CONTROLS(2); -OMAP_MCBSP_ST_CONTROLS(3); - -int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id) -{ - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - - if (!mcbsp->st_data) { - dev_warn(mcbsp->dev, "No sidetone data for port\n"); - return 0; - } - - switch (port_id) { - case 2: /* McBSP 2 */ - return snd_soc_add_dai_controls(cpu_dai, - omap_mcbsp2_st_controls, - ARRAY_SIZE(omap_mcbsp2_st_controls)); - case 3: /* McBSP 3 */ - return snd_soc_add_dai_controls(cpu_dai, - omap_mcbsp3_st_controls, - ARRAY_SIZE(omap_mcbsp3_st_controls)); - default: - dev_err(mcbsp->dev, "Port %d not supported\n", port_id); - break; - } - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls); diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c deleted file mode 100644 index a395598f1f20..000000000000 --- a/sound/soc/omap/omap-mcbsp.c +++ /dev/null @@ -1,1479 +0,0 @@ -/* - * omap-mcbsp.c -- OMAP ALSA SoC DAI driver using McBSP port - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> - * Peter Ujfalusi <peter.ujfalusi@ti.com> - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/pm_runtime.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/initval.h> -#include <sound/soc.h> -#include <sound/dmaengine_pcm.h> - -#include "omap-mcbsp-priv.h" -#include "omap-mcbsp.h" -#include "sdma-pcm.h" - -#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) - -enum { - OMAP_MCBSP_WORD_8 = 0, - OMAP_MCBSP_WORD_12, - OMAP_MCBSP_WORD_16, - OMAP_MCBSP_WORD_20, - OMAP_MCBSP_WORD_24, - OMAP_MCBSP_WORD_32, -}; - -static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp) -{ - dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id); - dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n", MCBSP_READ(mcbsp, DRR2)); - dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n", MCBSP_READ(mcbsp, DRR1)); - dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n", MCBSP_READ(mcbsp, DXR2)); - dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n", MCBSP_READ(mcbsp, DXR1)); - dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n", MCBSP_READ(mcbsp, SPCR2)); - dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n", MCBSP_READ(mcbsp, SPCR1)); - dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n", MCBSP_READ(mcbsp, RCR2)); - dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n", MCBSP_READ(mcbsp, RCR1)); - dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n", MCBSP_READ(mcbsp, XCR2)); - dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n", MCBSP_READ(mcbsp, XCR1)); - dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n", MCBSP_READ(mcbsp, SRGR2)); - dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n", MCBSP_READ(mcbsp, SRGR1)); - dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n", MCBSP_READ(mcbsp, PCR0)); - dev_dbg(mcbsp->dev, "***********************\n"); -} - -static int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id) -{ - struct clk *fck_src; - const char *src; - int r; - - if (fck_src_id == MCBSP_CLKS_PAD_SRC) - src = "pad_fck"; - else if (fck_src_id == MCBSP_CLKS_PRCM_SRC) - src = "prcm_fck"; - else - return -EINVAL; - - fck_src = clk_get(mcbsp->dev, src); - if (IS_ERR(fck_src)) { - dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src); - return -EINVAL; - } - - pm_runtime_put_sync(mcbsp->dev); - - r = clk_set_parent(mcbsp->fclk, fck_src); - if (r) { - dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n", - src); - clk_put(fck_src); - return r; - } - - pm_runtime_get_sync(mcbsp->dev); - - clk_put(fck_src); - - return 0; -} - -static irqreturn_t omap_mcbsp_irq_handler(int irq, void *data) -{ - struct omap_mcbsp *mcbsp = data; - u16 irqst; - - irqst = MCBSP_READ(mcbsp, IRQST); - dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n", irqst); - - if (irqst & RSYNCERREN) - dev_err(mcbsp->dev, "RX Frame Sync Error!\n"); - if (irqst & RFSREN) - dev_dbg(mcbsp->dev, "RX Frame Sync\n"); - if (irqst & REOFEN) - dev_dbg(mcbsp->dev, "RX End Of Frame\n"); - if (irqst & RRDYEN) - dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n"); - if (irqst & RUNDFLEN) - dev_err(mcbsp->dev, "RX Buffer Underflow!\n"); - if (irqst & ROVFLEN) - dev_err(mcbsp->dev, "RX Buffer Overflow!\n"); - - if (irqst & XSYNCERREN) - dev_err(mcbsp->dev, "TX Frame Sync Error!\n"); - if (irqst & XFSXEN) - dev_dbg(mcbsp->dev, "TX Frame Sync\n"); - if (irqst & XEOFEN) - dev_dbg(mcbsp->dev, "TX End Of Frame\n"); - if (irqst & XRDYEN) - dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n"); - if (irqst & XUNDFLEN) - dev_err(mcbsp->dev, "TX Buffer Underflow!\n"); - if (irqst & XOVFLEN) - dev_err(mcbsp->dev, "TX Buffer Overflow!\n"); - if (irqst & XEMPTYEOFEN) - dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n"); - - MCBSP_WRITE(mcbsp, IRQST, irqst); - - return IRQ_HANDLED; -} - -static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *data) -{ - struct omap_mcbsp *mcbsp = data; - u16 irqst_spcr2; - - irqst_spcr2 = MCBSP_READ(mcbsp, SPCR2); - dev_dbg(mcbsp->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2); - - if (irqst_spcr2 & XSYNC_ERR) { - dev_err(mcbsp->dev, "TX Frame Sync Error! : 0x%x\n", - irqst_spcr2); - /* Writing zero to XSYNC_ERR clears the IRQ */ - MCBSP_WRITE(mcbsp, SPCR2, MCBSP_READ_CACHE(mcbsp, SPCR2)); - } - - return IRQ_HANDLED; -} - -static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *data) -{ - struct omap_mcbsp *mcbsp = data; - u16 irqst_spcr1; - - irqst_spcr1 = MCBSP_READ(mcbsp, SPCR1); - dev_dbg(mcbsp->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1); - - if (irqst_spcr1 & RSYNC_ERR) { - dev_err(mcbsp->dev, "RX Frame Sync Error! : 0x%x\n", - irqst_spcr1); - /* Writing zero to RSYNC_ERR clears the IRQ */ - MCBSP_WRITE(mcbsp, SPCR1, MCBSP_READ_CACHE(mcbsp, SPCR1)); - } - - return IRQ_HANDLED; -} - -/* - * omap_mcbsp_config simply write a config to the - * appropriate McBSP. - * You either call this function or set the McBSP registers - * by yourself before calling omap_mcbsp_start(). - */ -static void omap_mcbsp_config(struct omap_mcbsp *mcbsp, - const struct omap_mcbsp_reg_cfg *config) -{ - dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n", - mcbsp->id, mcbsp->phys_base); - - /* We write the given config */ - MCBSP_WRITE(mcbsp, SPCR2, config->spcr2); - MCBSP_WRITE(mcbsp, SPCR1, config->spcr1); - MCBSP_WRITE(mcbsp, RCR2, config->rcr2); - MCBSP_WRITE(mcbsp, RCR1, config->rcr1); - MCBSP_WRITE(mcbsp, XCR2, config->xcr2); - MCBSP_WRITE(mcbsp, XCR1, config->xcr1); - MCBSP_WRITE(mcbsp, SRGR2, config->srgr2); - MCBSP_WRITE(mcbsp, SRGR1, config->srgr1); - MCBSP_WRITE(mcbsp, MCR2, config->mcr2); - MCBSP_WRITE(mcbsp, MCR1, config->mcr1); - MCBSP_WRITE(mcbsp, PCR0, config->pcr0); - if (mcbsp->pdata->has_ccr) { - MCBSP_WRITE(mcbsp, XCCR, config->xccr); - MCBSP_WRITE(mcbsp, RCCR, config->rccr); - } - /* Enable wakeup behavior */ - if (mcbsp->pdata->has_wakeup) - MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN); - - /* Enable TX/RX sync error interrupts by default */ - if (mcbsp->irq) - MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN | - RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN); -} - -/** - * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register - * @mcbsp: omap_mcbsp struct for the McBSP instance - * @stream: Stream direction (playback/capture) - * - * Returns the address of mcbsp data transmit register or data receive register - * to be used by DMA for transferring/receiving data - */ -static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp, - unsigned int stream) -{ - int data_reg; - - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (mcbsp->pdata->reg_size == 2) - data_reg = OMAP_MCBSP_REG_DXR1; - else - data_reg = OMAP_MCBSP_REG_DXR; - } else { - if (mcbsp->pdata->reg_size == 2) - data_reg = OMAP_MCBSP_REG_DRR1; - else - data_reg = OMAP_MCBSP_REG_DRR; - } - - return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step; -} - -/* - * omap_mcbsp_set_rx_threshold configures the transmit threshold in words. - * The threshold parameter is 1 based, and it is converted (threshold - 1) - * for the THRSH2 register. - */ -static void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold) -{ - if (threshold && threshold <= mcbsp->max_tx_thres) - MCBSP_WRITE(mcbsp, THRSH2, threshold - 1); -} - -/* - * omap_mcbsp_set_rx_threshold configures the receive threshold in words. - * The threshold parameter is 1 based, and it is converted (threshold - 1) - * for the THRSH1 register. - */ -static void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold) -{ - if (threshold && threshold <= mcbsp->max_rx_thres) - MCBSP_WRITE(mcbsp, THRSH1, threshold - 1); -} - -/* - * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO - */ -static u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp) -{ - u16 buffstat; - - /* Returns the number of free locations in the buffer */ - buffstat = MCBSP_READ(mcbsp, XBUFFSTAT); - - /* Number of slots are different in McBSP ports */ - return mcbsp->pdata->buffer_size - buffstat; -} - -/* - * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO - * to reach the threshold value (when the DMA will be triggered to read it) - */ -static u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp) -{ - u16 buffstat, threshold; - - /* Returns the number of used locations in the buffer */ - buffstat = MCBSP_READ(mcbsp, RBUFFSTAT); - /* RX threshold */ - threshold = MCBSP_READ(mcbsp, THRSH1); - - /* Return the number of location till we reach the threshold limit */ - if (threshold <= buffstat) - return 0; - else - return threshold - buffstat; -} - -static int omap_mcbsp_request(struct omap_mcbsp *mcbsp) -{ - void *reg_cache; - int err; - - reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL); - if (!reg_cache) - return -ENOMEM; - - spin_lock(&mcbsp->lock); - if (!mcbsp->free) { - dev_err(mcbsp->dev, "McBSP%d is currently in use\n", mcbsp->id); - err = -EBUSY; - goto err_kfree; - } - - mcbsp->free = false; - mcbsp->reg_cache = reg_cache; - spin_unlock(&mcbsp->lock); - - if(mcbsp->pdata->ops && mcbsp->pdata->ops->request) - mcbsp->pdata->ops->request(mcbsp->id - 1); - - /* - * Make sure that transmitter, receiver and sample-rate generator are - * not running before activating IRQs. - */ - MCBSP_WRITE(mcbsp, SPCR1, 0); - MCBSP_WRITE(mcbsp, SPCR2, 0); - - if (mcbsp->irq) { - err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0, - "McBSP", (void *)mcbsp); - if (err != 0) { - dev_err(mcbsp->dev, "Unable to request IRQ\n"); - goto err_clk_disable; - } - } else { - err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0, - "McBSP TX", (void *)mcbsp); - if (err != 0) { - dev_err(mcbsp->dev, "Unable to request TX IRQ\n"); - goto err_clk_disable; - } - - err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0, - "McBSP RX", (void *)mcbsp); - if (err != 0) { - dev_err(mcbsp->dev, "Unable to request RX IRQ\n"); - goto err_free_irq; - } - } - - return 0; -err_free_irq: - free_irq(mcbsp->tx_irq, (void *)mcbsp); -err_clk_disable: - if(mcbsp->pdata->ops && mcbsp->pdata->ops->free) - mcbsp->pdata->ops->free(mcbsp->id - 1); - - /* Disable wakeup behavior */ - if (mcbsp->pdata->has_wakeup) - MCBSP_WRITE(mcbsp, WAKEUPEN, 0); - - spin_lock(&mcbsp->lock); - mcbsp->free = true; - mcbsp->reg_cache = NULL; -err_kfree: - spin_unlock(&mcbsp->lock); - kfree(reg_cache); - - return err; -} - -static void omap_mcbsp_free(struct omap_mcbsp *mcbsp) -{ - void *reg_cache; - - if(mcbsp->pdata->ops && mcbsp->pdata->ops->free) - mcbsp->pdata->ops->free(mcbsp->id - 1); - - /* Disable wakeup behavior */ - if (mcbsp->pdata->has_wakeup) - MCBSP_WRITE(mcbsp, WAKEUPEN, 0); - - /* Disable interrupt requests */ - if (mcbsp->irq) - MCBSP_WRITE(mcbsp, IRQEN, 0); - - if (mcbsp->irq) { - free_irq(mcbsp->irq, (void *)mcbsp); - } else { - free_irq(mcbsp->rx_irq, (void *)mcbsp); - free_irq(mcbsp->tx_irq, (void *)mcbsp); - } - - reg_cache = mcbsp->reg_cache; - - /* - * Select CLKS source from internal source unconditionally before - * marking the McBSP port as free. - * If the external clock source via MCBSP_CLKS pin has been selected the - * system will refuse to enter idle if the CLKS pin source is not reset - * back to internal source. - */ - if (!mcbsp_omap1()) - omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC); - - spin_lock(&mcbsp->lock); - if (mcbsp->free) - dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id); - else - mcbsp->free = true; - mcbsp->reg_cache = NULL; - spin_unlock(&mcbsp->lock); - - kfree(reg_cache); -} - -/* - * Here we start the McBSP, by enabling transmitter, receiver or both. - * If no transmitter or receiver is active prior calling, then sample-rate - * generator and frame sync are started. - */ -static void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int stream) -{ - int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK); - int rx = !tx; - int enable_srg = 0; - u16 w; - - if (mcbsp->st_data) - omap_mcbsp_st_start(mcbsp); - - /* Only enable SRG, if McBSP is master */ - w = MCBSP_READ_CACHE(mcbsp, PCR0); - if (w & (FSXM | FSRM | CLKXM | CLKRM)) - enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | - MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); - - if (enable_srg) { - /* Start the sample generator */ - w = MCBSP_READ_CACHE(mcbsp, SPCR2); - MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6)); - } - - /* Enable transmitter and receiver */ - tx &= 1; - w = MCBSP_READ_CACHE(mcbsp, SPCR2); - MCBSP_WRITE(mcbsp, SPCR2, w | tx); - - rx &= 1; - w = MCBSP_READ_CACHE(mcbsp, SPCR1); - MCBSP_WRITE(mcbsp, SPCR1, w | rx); - - /* - * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec - * REVISIT: 100us may give enough time for two CLKSRG, however - * due to some unknown PM related, clock gating etc. reason it - * is now at 500us. - */ - udelay(500); - - if (enable_srg) { - /* Start frame sync */ - w = MCBSP_READ_CACHE(mcbsp, SPCR2); - MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7)); - } - - if (mcbsp->pdata->has_ccr) { - /* Release the transmitter and receiver */ - w = MCBSP_READ_CACHE(mcbsp, XCCR); - w &= ~(tx ? XDISABLE : 0); - MCBSP_WRITE(mcbsp, XCCR, w); - w = MCBSP_READ_CACHE(mcbsp, RCCR); - w &= ~(rx ? RDISABLE : 0); - MCBSP_WRITE(mcbsp, RCCR, w); - } - - /* Dump McBSP Regs */ - omap_mcbsp_dump_reg(mcbsp); -} - -static void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int stream) -{ - int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK); - int rx = !tx; - int idle; - u16 w; - - /* Reset transmitter */ - tx &= 1; - if (mcbsp->pdata->has_ccr) { - w = MCBSP_READ_CACHE(mcbsp, XCCR); - w |= (tx ? XDISABLE : 0); - MCBSP_WRITE(mcbsp, XCCR, w); - } - w = MCBSP_READ_CACHE(mcbsp, SPCR2); - MCBSP_WRITE(mcbsp, SPCR2, w & ~tx); - - /* Reset receiver */ - rx &= 1; - if (mcbsp->pdata->has_ccr) { - w = MCBSP_READ_CACHE(mcbsp, RCCR); - w |= (rx ? RDISABLE : 0); - MCBSP_WRITE(mcbsp, RCCR, w); - } - w = MCBSP_READ_CACHE(mcbsp, SPCR1); - MCBSP_WRITE(mcbsp, SPCR1, w & ~rx); - - idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | - MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); - - if (idle) { - /* Reset the sample rate generator */ - w = MCBSP_READ_CACHE(mcbsp, SPCR2); - MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6)); - } - - if (mcbsp->st_data) - omap_mcbsp_st_stop(mcbsp); -} - -#define max_thres(m) (mcbsp->pdata->buffer_size) -#define valid_threshold(m, val) ((val) <= max_thres(m)) -#define THRESHOLD_PROP_BUILDER(prop) \ -static ssize_t prop##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ - \ - return sprintf(buf, "%u\n", mcbsp->prop); \ -} \ - \ -static ssize_t prop##_store(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t size) \ -{ \ - struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ - unsigned long val; \ - int status; \ - \ - status = kstrtoul(buf, 0, &val); \ - if (status) \ - return status; \ - \ - if (!valid_threshold(mcbsp, val)) \ - return -EDOM; \ - \ - mcbsp->prop = val; \ - return size; \ -} \ - \ -static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store) - -THRESHOLD_PROP_BUILDER(max_tx_thres); -THRESHOLD_PROP_BUILDER(max_rx_thres); - -static const char * const dma_op_modes[] = { - "element", "threshold", -}; - -static ssize_t dma_op_mode_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); - int dma_op_mode, i = 0; - ssize_t len = 0; - const char * const *s; - - dma_op_mode = mcbsp->dma_op_mode; - - for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) { - if (dma_op_mode == i) - len += sprintf(buf + len, "[%s] ", *s); - else - len += sprintf(buf + len, "%s ", *s); - } - len += sprintf(buf + len, "\n"); - - return len; -} - -static ssize_t dma_op_mode_store(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t size) -{ - struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); - int i; - - i = sysfs_match_string(dma_op_modes, buf); - if (i < 0) - return i; - - spin_lock_irq(&mcbsp->lock); - if (!mcbsp->free) { - size = -EBUSY; - goto unlock; - } - mcbsp->dma_op_mode = i; - -unlock: - spin_unlock_irq(&mcbsp->lock); - - return size; -} - -static DEVICE_ATTR_RW(dma_op_mode); - -static const struct attribute *additional_attrs[] = { - &dev_attr_max_tx_thres.attr, - &dev_attr_max_rx_thres.attr, - &dev_attr_dma_op_mode.attr, - NULL, -}; - -static const struct attribute_group additional_attr_group = { - .attrs = (struct attribute **)additional_attrs, -}; - -/* - * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. - * 730 has only 2 McBSP, and both of them are MPU peripherals. - */ -static int omap_mcbsp_init(struct platform_device *pdev) -{ - struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); - struct resource *res; - int ret = 0; - - spin_lock_init(&mcbsp->lock); - mcbsp->free = true; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); - if (!res) - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(mcbsp->io_base)) - return PTR_ERR(mcbsp->io_base); - - mcbsp->phys_base = res->start; - mcbsp->reg_cache_size = resource_size(res); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); - if (!res) - mcbsp->phys_dma_base = mcbsp->phys_base; - else - mcbsp->phys_dma_base = res->start; - - /* - * OMAP1, 2 uses two interrupt lines: TX, RX - * OMAP2430, OMAP3 SoC have combined IRQ line as well. - * OMAP4 and newer SoC only have the combined IRQ line. - * Use the combined IRQ if available since it gives better debugging - * possibilities. - */ - mcbsp->irq = platform_get_irq_byname(pdev, "common"); - if (mcbsp->irq == -ENXIO) { - mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx"); - - if (mcbsp->tx_irq == -ENXIO) { - mcbsp->irq = platform_get_irq(pdev, 0); - mcbsp->tx_irq = 0; - } else { - mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx"); - mcbsp->irq = 0; - } - } - - if (!pdev->dev.of_node) { - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); - if (!res) { - dev_err(&pdev->dev, "invalid tx DMA channel\n"); - return -ENODEV; - } - mcbsp->dma_req[0] = res->start; - mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0]; - - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); - if (!res) { - dev_err(&pdev->dev, "invalid rx DMA channel\n"); - return -ENODEV; - } - mcbsp->dma_req[1] = res->start; - mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1]; - } else { - mcbsp->dma_data[0].filter_data = "tx"; - mcbsp->dma_data[1].filter_data = "rx"; - } - - mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp, - SNDRV_PCM_STREAM_PLAYBACK); - mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, - SNDRV_PCM_STREAM_CAPTURE); - - mcbsp->fclk = clk_get(&pdev->dev, "fck"); - if (IS_ERR(mcbsp->fclk)) { - ret = PTR_ERR(mcbsp->fclk); - dev_err(mcbsp->dev, "unable to get fck: %d\n", ret); - return ret; - } - - mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT; - if (mcbsp->pdata->buffer_size) { - /* - * Initially configure the maximum thresholds to a safe value. - * The McBSP FIFO usage with these values should not go under - * 16 locations. - * If the whole FIFO without safety buffer is used, than there - * is a possibility that the DMA will be not able to push the - * new data on time, causing channel shifts in runtime. - */ - mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10; - mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10; - - ret = sysfs_create_group(&mcbsp->dev->kobj, - &additional_attr_group); - if (ret) { - dev_err(mcbsp->dev, - "Unable to create additional controls\n"); - goto err_thres; - } - } - - ret = omap_mcbsp_st_init(pdev); - if (ret) - goto err_st; - - return 0; - -err_st: - if (mcbsp->pdata->buffer_size) - sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group); -err_thres: - clk_put(mcbsp->fclk); - return ret; -} - -/* - * Stream DMA parameters. DMA request line and port address are set runtime - * since they are different between OMAP1 and later OMAPs - */ -static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream, - unsigned int packet_size) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - int words; - - /* No need to proceed further if McBSP does not have FIFO */ - if (mcbsp->pdata->buffer_size == 0) - return; - - /* - * Configure McBSP threshold based on either: - * packet_size, when the sDMA is in packet mode, or based on the - * period size in THRESHOLD mode, otherwise use McBSP threshold = 1 - * for mono streams. - */ - if (packet_size) - words = packet_size; - else - words = 1; - - /* Configure McBSP internal buffer usage */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - omap_mcbsp_set_tx_threshold(mcbsp, words); - else - omap_mcbsp_set_rx_threshold(mcbsp, words); -} - -static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - struct snd_interval *buffer_size = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE); - struct snd_interval *channels = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct omap_mcbsp *mcbsp = rule->private; - struct snd_interval frames; - int size; - - snd_interval_any(&frames); - size = mcbsp->pdata->buffer_size; - - frames.min = size / channels->min; - frames.integer = 1; - return snd_interval_refine(buffer_size, &frames); -} - -static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) -{ - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - int err = 0; - - if (!cpu_dai->active) - err = omap_mcbsp_request(mcbsp); - - /* - * OMAP3 McBSP FIFO is word structured. - * McBSP2 has 1024 + 256 = 1280 word long buffer, - * McBSP1,3,4,5 has 128 word long buffer - * This means that the size of the FIFO depends on the sample format. - * For example on McBSP3: - * 16bit samples: size is 128 * 2 = 256 bytes - * 32bit samples: size is 128 * 4 = 512 bytes - * It is simpler to place constraint for buffer and period based on - * channels. - * McBSP3 as example again (16 or 32 bit samples): - * 1 channel (mono): size is 128 frames (128 words) - * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words) - * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words) - */ - if (mcbsp->pdata->buffer_size) { - /* - * Rule for the buffer size. We should not allow - * smaller buffer than the FIFO size to avoid underruns. - * This applies only for the playback stream. - */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_pcm_hw_rule_add(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - omap_mcbsp_hwrule_min_buffersize, - mcbsp, - SNDRV_PCM_HW_PARAM_CHANNELS, -1); - - /* Make sure, that the period size is always even */ - snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2); - } - - return err; -} - -static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) -{ - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); - int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; - int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; - - if (mcbsp->latency[stream2]) - pm_qos_update_request(&mcbsp->pm_qos_req, - mcbsp->latency[stream2]); - else if (mcbsp->latency[stream1]) - pm_qos_remove_request(&mcbsp->pm_qos_req); - - mcbsp->latency[stream1] = 0; - - if (!cpu_dai->active) { - omap_mcbsp_free(mcbsp); - mcbsp->configured = 0; - } -} - -static int omap_mcbsp_dai_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) -{ - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - struct pm_qos_request *pm_qos_req = &mcbsp->pm_qos_req; - int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); - int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; - int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; - int latency = mcbsp->latency[stream2]; - - /* Prevent omap hardware from hitting off between FIFO fills */ - if (!latency || mcbsp->latency[stream1] < latency) - latency = mcbsp->latency[stream1]; - - if (pm_qos_request_active(pm_qos_req)) - pm_qos_update_request(pm_qos_req, latency); - else if (latency) - pm_qos_add_request(pm_qos_req, PM_QOS_CPU_DMA_LATENCY, latency); - - return 0; -} - -static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *cpu_dai) -{ - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - mcbsp->active++; - omap_mcbsp_start(mcbsp, substream->stream); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - omap_mcbsp_stop(mcbsp, substream->stream); - mcbsp->active--; - break; - default: - return -EINVAL; - } - - return 0; -} - -static snd_pcm_sframes_t omap_mcbsp_dai_delay( - struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - u16 fifo_use; - snd_pcm_sframes_t delay; - - /* No need to proceed further if McBSP does not have FIFO */ - if (mcbsp->pdata->buffer_size == 0) - return 0; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - fifo_use = omap_mcbsp_get_tx_delay(mcbsp); - else - fifo_use = omap_mcbsp_get_rx_delay(mcbsp); - - /* - * Divide the used locations with the channel count to get the - * FIFO usage in samples (don't care about partial samples in the - * buffer). - */ - delay = fifo_use / substream->runtime->channels; - - return delay; -} - -static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *cpu_dai) -{ - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; - struct snd_dmaengine_dai_dma_data *dma_data; - int wlen, channels, wpf; - int pkt_size = 0; - unsigned int format, div, framesize, master; - unsigned int buffer_size = mcbsp->pdata->buffer_size; - - dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream); - channels = params_channels(params); - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - wlen = 16; - break; - case SNDRV_PCM_FORMAT_S32_LE: - wlen = 32; - break; - default: - return -EINVAL; - } - if (buffer_size) { - int latency; - - if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) { - int period_words, max_thrsh; - int divider = 0; - - period_words = params_period_bytes(params) / (wlen / 8); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - max_thrsh = mcbsp->max_tx_thres; - else - max_thrsh = mcbsp->max_rx_thres; - /* - * Use sDMA packet mode if McBSP is in threshold mode: - * If period words less than the FIFO size the packet - * size is set to the number of period words, otherwise - * Look for the biggest threshold value which divides - * the period size evenly. - */ - divider = period_words / max_thrsh; - if (period_words % max_thrsh) - divider++; - while (period_words % divider && - divider < period_words) - divider++; - if (divider == period_words) - return -EINVAL; - - pkt_size = period_words / divider; - } else if (channels > 1) { - /* Use packet mode for non mono streams */ - pkt_size = channels; - } - - latency = (buffer_size - pkt_size) / channels; - latency = latency * USEC_PER_SEC / - (params->rate_num / params->rate_den); - mcbsp->latency[substream->stream] = latency; - - omap_mcbsp_set_threshold(substream, pkt_size); - } - - dma_data->maxburst = pkt_size; - - if (mcbsp->configured) { - /* McBSP already configured by another stream */ - return 0; - } - - regs->rcr2 &= ~(RPHASE | RFRLEN2(0x7f) | RWDLEN2(7)); - regs->xcr2 &= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7)); - regs->rcr1 &= ~(RFRLEN1(0x7f) | RWDLEN1(7)); - regs->xcr1 &= ~(XFRLEN1(0x7f) | XWDLEN1(7)); - format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK; - wpf = channels; - if (channels == 2 && (format == SND_SOC_DAIFMT_I2S || - format == SND_SOC_DAIFMT_LEFT_J)) { - /* Use dual-phase frames */ - regs->rcr2 |= RPHASE; - regs->xcr2 |= XPHASE; - /* Set 1 word per (McBSP) frame for phase1 and phase2 */ - wpf--; - regs->rcr2 |= RFRLEN2(wpf - 1); - regs->xcr2 |= XFRLEN2(wpf - 1); - } - - regs->rcr1 |= RFRLEN1(wpf - 1); - regs->xcr1 |= XFRLEN1(wpf - 1); - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - /* Set word lengths */ - regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16); - regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16); - regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16); - regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_16); - break; - case SNDRV_PCM_FORMAT_S32_LE: - /* Set word lengths */ - regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_32); - regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32); - regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_32); - regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_32); - break; - default: - /* Unsupported PCM format */ - return -EINVAL; - } - - /* In McBSP master modes, FRAME (i.e. sample rate) is generated - * by _counting_ BCLKs. Calculate frame size in BCLKs */ - master = mcbsp->fmt & SND_SOC_DAIFMT_MASTER_MASK; - if (master == SND_SOC_DAIFMT_CBS_CFS) { - div = mcbsp->clk_div ? mcbsp->clk_div : 1; - framesize = (mcbsp->in_freq / div) / params_rate(params); - - if (framesize < wlen * channels) { - printk(KERN_ERR "%s: not enough bandwidth for desired rate and " - "channels\n", __func__); - return -EINVAL; - } - } else - framesize = wlen * channels; - - /* Set FS period and length in terms of bit clock periods */ - regs->srgr2 &= ~FPER(0xfff); - regs->srgr1 &= ~FWID(0xff); - switch (format) { - case SND_SOC_DAIFMT_I2S: - case SND_SOC_DAIFMT_LEFT_J: - regs->srgr2 |= FPER(framesize - 1); - regs->srgr1 |= FWID((framesize >> 1) - 1); - break; - case SND_SOC_DAIFMT_DSP_A: - case SND_SOC_DAIFMT_DSP_B: - regs->srgr2 |= FPER(framesize - 1); - regs->srgr1 |= FWID(0); - break; - } - - omap_mcbsp_config(mcbsp, &mcbsp->cfg_regs); - mcbsp->wlen = wlen; - mcbsp->configured = 1; - - return 0; -} - -/* - * This must be called before _set_clkdiv and _set_sysclk since McBSP register - * cache is initialized here - */ -static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, - unsigned int fmt) -{ - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; - bool inv_fs = false; - - if (mcbsp->configured) - return 0; - - mcbsp->fmt = fmt; - memset(regs, 0, sizeof(*regs)); - /* Generic McBSP register settings */ - regs->spcr2 |= XINTM(3) | FREE; - regs->spcr1 |= RINTM(3); - /* RFIG and XFIG are not defined in 2430 and on OMAP3+ */ - if (!mcbsp->pdata->has_ccr) { - regs->rcr2 |= RFIG; - regs->xcr2 |= XFIG; - } - - /* Configure XCCR/RCCR only for revisions which have ccr registers */ - if (mcbsp->pdata->has_ccr) { - regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE; - regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE; - } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - /* 1-bit data delay */ - regs->rcr2 |= RDATDLY(1); - regs->xcr2 |= XDATDLY(1); - break; - case SND_SOC_DAIFMT_LEFT_J: - /* 0-bit data delay */ - regs->rcr2 |= RDATDLY(0); - regs->xcr2 |= XDATDLY(0); - regs->spcr1 |= RJUST(2); - /* Invert FS polarity configuration */ - inv_fs = true; - break; - case SND_SOC_DAIFMT_DSP_A: - /* 1-bit data delay */ - regs->rcr2 |= RDATDLY(1); - regs->xcr2 |= XDATDLY(1); - /* Invert FS polarity configuration */ - inv_fs = true; - break; - case SND_SOC_DAIFMT_DSP_B: - /* 0-bit data delay */ - regs->rcr2 |= RDATDLY(0); - regs->xcr2 |= XDATDLY(0); - /* Invert FS polarity configuration */ - inv_fs = true; - break; - default: - /* Unsupported data format */ - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* McBSP master. Set FS and bit clocks as outputs */ - regs->pcr0 |= FSXM | FSRM | - CLKXM | CLKRM; - /* Sample rate generator drives the FS */ - regs->srgr2 |= FSGM; - break; - case SND_SOC_DAIFMT_CBM_CFS: - /* McBSP slave. FS clock as output */ - regs->srgr2 |= FSGM; - regs->pcr0 |= FSXM | FSRM; - break; - case SND_SOC_DAIFMT_CBM_CFM: - /* McBSP slave */ - break; - default: - /* Unsupported master/slave configuration */ - return -EINVAL; - } - - /* Set bit clock (CLKX/CLKR) and FS polarities */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - /* - * Normal BCLK + FS. - * FS active low. TX data driven on falling edge of bit clock - * and RX data sampled on rising edge of bit clock. - */ - regs->pcr0 |= FSXP | FSRP | - CLKXP | CLKRP; - break; - case SND_SOC_DAIFMT_NB_IF: - regs->pcr0 |= CLKXP | CLKRP; - break; - case SND_SOC_DAIFMT_IB_NF: - regs->pcr0 |= FSXP | FSRP; - break; - case SND_SOC_DAIFMT_IB_IF: - break; - default: - return -EINVAL; - } - if (inv_fs == true) - regs->pcr0 ^= FSXP | FSRP; - - return 0; -} - -static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, - int div_id, int div) -{ - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; - - if (div_id != OMAP_MCBSP_CLKGDV) - return -ENODEV; - - mcbsp->clk_div = div; - regs->srgr1 &= ~CLKGDV(0xff); - regs->srgr1 |= CLKGDV(div - 1); - - return 0; -} - -static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, - int dir) -{ - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); - struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; - int err = 0; - - if (mcbsp->active) { - if (freq == mcbsp->in_freq) - return 0; - else - return -EBUSY; - } - - mcbsp->in_freq = freq; - regs->srgr2 &= ~CLKSM; - regs->pcr0 &= ~SCLKME; - - switch (clk_id) { - case OMAP_MCBSP_SYSCLK_CLK: - regs->srgr2 |= CLKSM; - break; - case OMAP_MCBSP_SYSCLK_CLKS_FCLK: - if (mcbsp_omap1()) { - err = -EINVAL; - break; - } - err = omap2_mcbsp_set_clks_src(mcbsp, - MCBSP_CLKS_PRCM_SRC); - break; - case OMAP_MCBSP_SYSCLK_CLKS_EXT: - if (mcbsp_omap1()) { - err = 0; - break; - } - err = omap2_mcbsp_set_clks_src(mcbsp, - MCBSP_CLKS_PAD_SRC); - break; - - case OMAP_MCBSP_SYSCLK_CLKX_EXT: - regs->srgr2 |= CLKSM; - regs->pcr0 |= SCLKME; - /* - * If McBSP is master but yet the CLKX/CLKR pin drives the SRG, - * disable output on those pins. This enables to inject the - * reference clock through CLKX/CLKR. For this to work - * set_dai_sysclk() _needs_ to be called after set_dai_fmt(). - */ - regs->pcr0 &= ~CLKXM; - break; - case OMAP_MCBSP_SYSCLK_CLKR_EXT: - regs->pcr0 |= SCLKME; - /* Disable ouput on CLKR pin in master mode */ - regs->pcr0 &= ~CLKRM; - break; - default: - err = -ENODEV; - } - - return err; -} - -static const struct snd_soc_dai_ops mcbsp_dai_ops = { - .startup = omap_mcbsp_dai_startup, - .shutdown = omap_mcbsp_dai_shutdown, - .prepare = omap_mcbsp_dai_prepare, - .trigger = omap_mcbsp_dai_trigger, - .delay = omap_mcbsp_dai_delay, - .hw_params = omap_mcbsp_dai_hw_params, - .set_fmt = omap_mcbsp_dai_set_dai_fmt, - .set_clkdiv = omap_mcbsp_dai_set_clkdiv, - .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, -}; - -static int omap_mcbsp_probe(struct snd_soc_dai *dai) -{ - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai); - - pm_runtime_enable(mcbsp->dev); - - snd_soc_dai_init_dma_data(dai, - &mcbsp->dma_data[SNDRV_PCM_STREAM_PLAYBACK], - &mcbsp->dma_data[SNDRV_PCM_STREAM_CAPTURE]); - - return 0; -} - -static int omap_mcbsp_remove(struct snd_soc_dai *dai) -{ - struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai); - - pm_runtime_disable(mcbsp->dev); - - return 0; -} - -static struct snd_soc_dai_driver omap_mcbsp_dai = { - .probe = omap_mcbsp_probe, - .remove = omap_mcbsp_remove, - .playback = { - .channels_min = 1, - .channels_max = 16, - .rates = OMAP_MCBSP_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, - }, - .capture = { - .channels_min = 1, - .channels_max = 16, - .rates = OMAP_MCBSP_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, - }, - .ops = &mcbsp_dai_ops, -}; - -static const struct snd_soc_component_driver omap_mcbsp_component = { - .name = "omap-mcbsp", -}; - -static struct omap_mcbsp_platform_data omap2420_pdata = { - .reg_step = 4, - .reg_size = 2, -}; - -static struct omap_mcbsp_platform_data omap2430_pdata = { - .reg_step = 4, - .reg_size = 4, - .has_ccr = true, -}; - -static struct omap_mcbsp_platform_data omap3_pdata = { - .reg_step = 4, - .reg_size = 4, - .has_ccr = true, - .has_wakeup = true, -}; - -static struct omap_mcbsp_platform_data omap4_pdata = { - .reg_step = 4, - .reg_size = 4, - .has_ccr = true, - .has_wakeup = true, -}; - -static const struct of_device_id omap_mcbsp_of_match[] = { - { - .compatible = "ti,omap2420-mcbsp", - .data = &omap2420_pdata, - }, - { - .compatible = "ti,omap2430-mcbsp", - .data = &omap2430_pdata, - }, - { - .compatible = "ti,omap3-mcbsp", - .data = &omap3_pdata, - }, - { - .compatible = "ti,omap4-mcbsp", - .data = &omap4_pdata, - }, - { }, -}; -MODULE_DEVICE_TABLE(of, omap_mcbsp_of_match); - -static int asoc_mcbsp_probe(struct platform_device *pdev) -{ - struct omap_mcbsp_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct omap_mcbsp *mcbsp; - const struct of_device_id *match; - int ret; - - match = of_match_device(omap_mcbsp_of_match, &pdev->dev); - if (match) { - struct device_node *node = pdev->dev.of_node; - struct omap_mcbsp_platform_data *pdata_quirk = pdata; - int buffer_size; - - pdata = devm_kzalloc(&pdev->dev, - sizeof(struct omap_mcbsp_platform_data), - GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - memcpy(pdata, match->data, sizeof(*pdata)); - if (!of_property_read_u32(node, "ti,buffer-size", &buffer_size)) - pdata->buffer_size = buffer_size; - if (pdata_quirk) - pdata->force_ick_on = pdata_quirk->force_ick_on; - } else if (!pdata) { - dev_err(&pdev->dev, "missing platform data.\n"); - return -EINVAL; - } - mcbsp = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcbsp), GFP_KERNEL); - if (!mcbsp) - return -ENOMEM; - - mcbsp->id = pdev->id; - mcbsp->pdata = pdata; - mcbsp->dev = &pdev->dev; - platform_set_drvdata(pdev, mcbsp); - - ret = omap_mcbsp_init(pdev); - if (ret) - return ret; - - if (mcbsp->pdata->reg_size == 2) { - omap_mcbsp_dai.playback.formats = SNDRV_PCM_FMTBIT_S16_LE; - omap_mcbsp_dai.capture.formats = SNDRV_PCM_FMTBIT_S16_LE; - } - - ret = devm_snd_soc_register_component(&pdev->dev, - &omap_mcbsp_component, - &omap_mcbsp_dai, 1); - if (ret) - return ret; - - return sdma_pcm_platform_register(&pdev->dev, NULL, NULL); -} - -static int asoc_mcbsp_remove(struct platform_device *pdev) -{ - struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); - - if (mcbsp->pdata->ops && mcbsp->pdata->ops->free) - mcbsp->pdata->ops->free(mcbsp->id); - - if (pm_qos_request_active(&mcbsp->pm_qos_req)) - pm_qos_remove_request(&mcbsp->pm_qos_req); - - if (mcbsp->pdata->buffer_size) - sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group); - - omap_mcbsp_st_cleanup(pdev); - - clk_put(mcbsp->fclk); - - return 0; -} - -static struct platform_driver asoc_mcbsp_driver = { - .driver = { - .name = "omap-mcbsp", - .of_match_table = omap_mcbsp_of_match, - }, - - .probe = asoc_mcbsp_probe, - .remove = asoc_mcbsp_remove, -}; - -module_platform_driver(asoc_mcbsp_driver); - -MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>"); -MODULE_DESCRIPTION("OMAP I2S SoC Interface"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:omap-mcbsp"); diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h deleted file mode 100644 index 7911d24898c9..000000000000 --- a/sound/soc/omap/omap-mcbsp.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * omap-mcbsp.h - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> - * Peter Ujfalusi <peter.ujfalusi@ti.com> - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __OMAP_MCBSP_H__ -#define __OMAP_MCBSP_H__ - -#include <sound/dmaengine_pcm.h> - -/* Source clocks for McBSP sample rate generator */ -enum omap_mcbsp_clksrg_clk { - OMAP_MCBSP_SYSCLK_CLKS_FCLK, /* Internal FCLK */ - OMAP_MCBSP_SYSCLK_CLKS_EXT, /* External CLKS pin */ - OMAP_MCBSP_SYSCLK_CLK, /* Internal ICLK */ - OMAP_MCBSP_SYSCLK_CLKX_EXT, /* External CLKX pin */ - OMAP_MCBSP_SYSCLK_CLKR_EXT, /* External CLKR pin */ -}; - -/* McBSP dividers */ -enum omap_mcbsp_div { - OMAP_MCBSP_CLKGDV, /* Sample rate generator divider */ -}; - -int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id); - -#endif /* __OMAP_MCBSP_H__ */ diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c deleted file mode 100644 index 7d5bdc5a2890..000000000000 --- a/sound/soc/omap/omap-mcpdm.c +++ /dev/null @@ -1,619 +0,0 @@ -/* - * omap-mcpdm.c -- OMAP ALSA SoC DAI driver using McPDM port - * - * Copyright (C) 2009 - 2011 Texas Instruments - * - * Author: Misael Lopez Cruz <misael.lopez@ti.com> - * Contact: Jorge Eduardo Candelaria <x0107209@ti.com> - * Margarita Olaya <magi.olaya@ti.com> - * Peter Ujfalusi <peter.ujfalusi@ti.com> - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/slab.h> -#include <linux/pm_runtime.h> -#include <linux/of_device.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/dmaengine_pcm.h> - -#include "omap-mcpdm.h" -#include "sdma-pcm.h" - -struct mcpdm_link_config { - u32 link_mask; /* channel mask for the direction */ - u32 threshold; /* FIFO threshold */ -}; - -struct omap_mcpdm { - struct device *dev; - unsigned long phys_base; - void __iomem *io_base; - int irq; - struct pm_qos_request pm_qos_req; - int latency[2]; - - struct mutex mutex; - - /* Playback/Capture configuration */ - struct mcpdm_link_config config[2]; - - /* McPDM dn offsets for rx1, and 2 channels */ - u32 dn_rx_offset; - - /* McPDM needs to be restarted due to runtime reconfiguration */ - bool restart; - - /* pm state for suspend/resume handling */ - int pm_active_count; - - struct snd_dmaengine_dai_dma_data dma_data[2]; -}; - -/* - * Stream DMA parameters - */ - -static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val) -{ - writel_relaxed(val, mcpdm->io_base + reg); -} - -static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg) -{ - return readl_relaxed(mcpdm->io_base + reg); -} - -#ifdef DEBUG -static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) -{ - dev_dbg(mcpdm->dev, "***********************\n"); - dev_dbg(mcpdm->dev, "IRQSTATUS_RAW: 0x%04x\n", - omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS_RAW)); - dev_dbg(mcpdm->dev, "IRQSTATUS: 0x%04x\n", - omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS)); - dev_dbg(mcpdm->dev, "IRQENABLE_SET: 0x%04x\n", - omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_SET)); - dev_dbg(mcpdm->dev, "IRQENABLE_CLR: 0x%04x\n", - omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_CLR)); - dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n", - omap_mcpdm_read(mcpdm, MCPDM_REG_IRQWAKE_EN)); - dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n", - omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_SET)); - dev_dbg(mcpdm->dev, "DMAENABLE_CLR: 0x%04x\n", - omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_CLR)); - dev_dbg(mcpdm->dev, "DMAWAKEEN: 0x%04x\n", - omap_mcpdm_read(mcpdm, MCPDM_REG_DMAWAKEEN)); - dev_dbg(mcpdm->dev, "CTRL: 0x%04x\n", - omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL)); - dev_dbg(mcpdm->dev, "DN_DATA: 0x%04x\n", - omap_mcpdm_read(mcpdm, MCPDM_REG_DN_DATA)); - dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n", - omap_mcpdm_read(mcpdm, MCPDM_REG_UP_DATA)); - dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n", - omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_DN)); - dev_dbg(mcpdm->dev, "FIFO_CTRL_UP: 0x%04x\n", - omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_UP)); - dev_dbg(mcpdm->dev, "***********************\n"); -} -#else -static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {} -#endif - -/* - * Enables the transfer through the PDM interface to/from the Phoenix - * codec by enabling the corresponding UP or DN channels. - */ -static void omap_mcpdm_start(struct omap_mcpdm *mcpdm) -{ - u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); - u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask; - - ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); - omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); - - ctrl |= link_mask; - omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); - - ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); - omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); -} - -/* - * Disables the transfer through the PDM interface to/from the Phoenix - * codec by disabling the corresponding UP or DN channels. - */ -static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm) -{ - u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); - u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK; - - ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); - omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); - - ctrl &= ~(link_mask); - omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); - - ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); - omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); - -} - -/* - * Is the physical McPDM interface active. - */ -static inline int omap_mcpdm_active(struct omap_mcpdm *mcpdm) -{ - return omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL) & - (MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK); -} - -/* - * Configures McPDM uplink, and downlink for audio. - * This function should be called before omap_mcpdm_start. - */ -static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm) -{ - u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); - - omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl | MCPDM_WD_EN); - - omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_SET, - MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL | - MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL); - - /* Enable DN RX1/2 offset cancellation feature, if configured */ - if (mcpdm->dn_rx_offset) { - u32 dn_offset = mcpdm->dn_rx_offset; - - omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset); - dn_offset |= (MCPDM_DN_OFST_RX1_EN | MCPDM_DN_OFST_RX2_EN); - omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset); - } - - omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, - mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold); - omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, - mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold); - - omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET, - MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE); -} - -/* - * Cleans McPDM uplink, and downlink configuration. - * This function should be called when the stream is closed. - */ -static void omap_mcpdm_close_streams(struct omap_mcpdm *mcpdm) -{ - /* Disable irq request generation for downlink */ - omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR, - MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL); - - /* Disable DMA request generation for downlink */ - omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_DN_ENABLE); - - /* Disable irq request generation for uplink */ - omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR, - MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL); - - /* Disable DMA request generation for uplink */ - omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_UP_ENABLE); - - /* Disable RX1/2 offset cancellation */ - if (mcpdm->dn_rx_offset) - omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, 0); -} - -static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id) -{ - struct omap_mcpdm *mcpdm = dev_id; - int irq_status; - - irq_status = omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS); - - /* Acknowledge irq event */ - omap_mcpdm_write(mcpdm, MCPDM_REG_IRQSTATUS, irq_status); - - if (irq_status & MCPDM_DN_IRQ_FULL) - dev_dbg(mcpdm->dev, "DN (playback) FIFO Full\n"); - - if (irq_status & MCPDM_DN_IRQ_EMPTY) - dev_dbg(mcpdm->dev, "DN (playback) FIFO Empty\n"); - - if (irq_status & MCPDM_DN_IRQ) - dev_dbg(mcpdm->dev, "DN (playback) write request\n"); - - if (irq_status & MCPDM_UP_IRQ_FULL) - dev_dbg(mcpdm->dev, "UP (capture) FIFO Full\n"); - - if (irq_status & MCPDM_UP_IRQ_EMPTY) - dev_dbg(mcpdm->dev, "UP (capture) FIFO Empty\n"); - - if (irq_status & MCPDM_UP_IRQ) - dev_dbg(mcpdm->dev, "UP (capture) write request\n"); - - return IRQ_HANDLED; -} - -static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); - - mutex_lock(&mcpdm->mutex); - - if (!dai->active) - omap_mcpdm_open_streams(mcpdm); - - mutex_unlock(&mcpdm->mutex); - - return 0; -} - -static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); - int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); - int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; - int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; - - mutex_lock(&mcpdm->mutex); - - if (!dai->active) { - if (omap_mcpdm_active(mcpdm)) { - omap_mcpdm_stop(mcpdm); - omap_mcpdm_close_streams(mcpdm); - mcpdm->config[0].link_mask = 0; - mcpdm->config[1].link_mask = 0; - } - } - - if (mcpdm->latency[stream2]) - pm_qos_update_request(&mcpdm->pm_qos_req, - mcpdm->latency[stream2]); - else if (mcpdm->latency[stream1]) - pm_qos_remove_request(&mcpdm->pm_qos_req); - - mcpdm->latency[stream1] = 0; - - mutex_unlock(&mcpdm->mutex); -} - -static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); - int stream = substream->stream; - struct snd_dmaengine_dai_dma_data *dma_data; - u32 threshold; - int channels, latency; - int link_mask = 0; - - channels = params_channels(params); - switch (channels) { - case 5: - if (stream == SNDRV_PCM_STREAM_CAPTURE) - /* up to 3 channels for capture */ - return -EINVAL; - link_mask |= 1 << 4; - /* fall through */ - case 4: - if (stream == SNDRV_PCM_STREAM_CAPTURE) - /* up to 3 channels for capture */ - return -EINVAL; - link_mask |= 1 << 3; - /* fall through */ - case 3: - link_mask |= 1 << 2; - /* fall through */ - case 2: - link_mask |= 1 << 1; - /* fall through */ - case 1: - link_mask |= 1 << 0; - break; - default: - /* unsupported number of channels */ - return -EINVAL; - } - - dma_data = snd_soc_dai_get_dma_data(dai, substream); - - threshold = mcpdm->config[stream].threshold; - /* Configure McPDM channels, and DMA packet size */ - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - link_mask <<= 3; - - /* If capture is not running assume a stereo stream to come */ - if (!mcpdm->config[!stream].link_mask) - mcpdm->config[!stream].link_mask = 0x3; - - dma_data->maxburst = - (MCPDM_DN_THRES_MAX - threshold) * channels; - latency = threshold; - } else { - /* If playback is not running assume a stereo stream to come */ - if (!mcpdm->config[!stream].link_mask) - mcpdm->config[!stream].link_mask = (0x3 << 3); - - dma_data->maxburst = threshold * channels; - latency = (MCPDM_DN_THRES_MAX - threshold); - } - - /* - * The DMA must act to a DMA request within latency time (usec) to avoid - * under/overflow - */ - mcpdm->latency[stream] = latency * USEC_PER_SEC / params_rate(params); - - if (!mcpdm->latency[stream]) - mcpdm->latency[stream] = 10; - - /* Check if we need to restart McPDM with this stream */ - if (mcpdm->config[stream].link_mask && - mcpdm->config[stream].link_mask != link_mask) - mcpdm->restart = true; - - mcpdm->config[stream].link_mask = link_mask; - - return 0; -} - -static int omap_mcpdm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); - struct pm_qos_request *pm_qos_req = &mcpdm->pm_qos_req; - int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); - int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; - int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; - int latency = mcpdm->latency[stream2]; - - /* Prevent omap hardware from hitting off between FIFO fills */ - if (!latency || mcpdm->latency[stream1] < latency) - latency = mcpdm->latency[stream1]; - - if (pm_qos_request_active(pm_qos_req)) - pm_qos_update_request(pm_qos_req, latency); - else if (latency) - pm_qos_add_request(pm_qos_req, PM_QOS_CPU_DMA_LATENCY, latency); - - if (!omap_mcpdm_active(mcpdm)) { - omap_mcpdm_start(mcpdm); - omap_mcpdm_reg_dump(mcpdm); - } else if (mcpdm->restart) { - omap_mcpdm_stop(mcpdm); - omap_mcpdm_start(mcpdm); - mcpdm->restart = false; - omap_mcpdm_reg_dump(mcpdm); - } - - return 0; -} - -static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = { - .startup = omap_mcpdm_dai_startup, - .shutdown = omap_mcpdm_dai_shutdown, - .hw_params = omap_mcpdm_dai_hw_params, - .prepare = omap_mcpdm_prepare, -}; - -static int omap_mcpdm_probe(struct snd_soc_dai *dai) -{ - struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); - int ret; - - pm_runtime_enable(mcpdm->dev); - - /* Disable lines while request is ongoing */ - pm_runtime_get_sync(mcpdm->dev); - omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00); - - ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, 0, "McPDM", - (void *)mcpdm); - - pm_runtime_put_sync(mcpdm->dev); - - if (ret) { - dev_err(mcpdm->dev, "Request for IRQ failed\n"); - pm_runtime_disable(mcpdm->dev); - } - - /* Configure McPDM threshold values */ - mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2; - mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold = - MCPDM_UP_THRES_MAX - 3; - - snd_soc_dai_init_dma_data(dai, - &mcpdm->dma_data[SNDRV_PCM_STREAM_PLAYBACK], - &mcpdm->dma_data[SNDRV_PCM_STREAM_CAPTURE]); - - return ret; -} - -static int omap_mcpdm_remove(struct snd_soc_dai *dai) -{ - struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); - - free_irq(mcpdm->irq, (void *)mcpdm); - pm_runtime_disable(mcpdm->dev); - - if (pm_qos_request_active(&mcpdm->pm_qos_req)) - pm_qos_remove_request(&mcpdm->pm_qos_req); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int omap_mcpdm_suspend(struct snd_soc_dai *dai) -{ - struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); - - if (dai->active) { - omap_mcpdm_stop(mcpdm); - omap_mcpdm_close_streams(mcpdm); - } - - mcpdm->pm_active_count = 0; - while (pm_runtime_active(mcpdm->dev)) { - pm_runtime_put_sync(mcpdm->dev); - mcpdm->pm_active_count++; - } - - return 0; -} - -static int omap_mcpdm_resume(struct snd_soc_dai *dai) -{ - struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); - - if (mcpdm->pm_active_count) { - while (mcpdm->pm_active_count--) - pm_runtime_get_sync(mcpdm->dev); - - if (dai->active) { - omap_mcpdm_open_streams(mcpdm); - omap_mcpdm_start(mcpdm); - } - } - - - return 0; -} -#else -#define omap_mcpdm_suspend NULL -#define omap_mcpdm_resume NULL -#endif - -#define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) -#define OMAP_MCPDM_FORMATS SNDRV_PCM_FMTBIT_S32_LE - -static struct snd_soc_dai_driver omap_mcpdm_dai = { - .probe = omap_mcpdm_probe, - .remove = omap_mcpdm_remove, - .suspend = omap_mcpdm_suspend, - .resume = omap_mcpdm_resume, - .probe_order = SND_SOC_COMP_ORDER_LATE, - .remove_order = SND_SOC_COMP_ORDER_EARLY, - .playback = { - .channels_min = 1, - .channels_max = 5, - .rates = OMAP_MCPDM_RATES, - .formats = OMAP_MCPDM_FORMATS, - .sig_bits = 24, - }, - .capture = { - .channels_min = 1, - .channels_max = 3, - .rates = OMAP_MCPDM_RATES, - .formats = OMAP_MCPDM_FORMATS, - .sig_bits = 24, - }, - .ops = &omap_mcpdm_dai_ops, -}; - -static const struct snd_soc_component_driver omap_mcpdm_component = { - .name = "omap-mcpdm", -}; - -void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd, - u8 rx1, u8 rx2) -{ - struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(rtd->cpu_dai); - - mcpdm->dn_rx_offset = MCPDM_DNOFST_RX1(rx1) | MCPDM_DNOFST_RX2(rx2); -} -EXPORT_SYMBOL_GPL(omap_mcpdm_configure_dn_offsets); - -static int asoc_mcpdm_probe(struct platform_device *pdev) -{ - struct omap_mcpdm *mcpdm; - struct resource *res; - int ret; - - mcpdm = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcpdm), GFP_KERNEL); - if (!mcpdm) - return -ENOMEM; - - platform_set_drvdata(pdev, mcpdm); - - mutex_init(&mcpdm->mutex); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); - if (res == NULL) - return -ENOMEM; - - mcpdm->dma_data[0].addr = res->start + MCPDM_REG_DN_DATA; - mcpdm->dma_data[1].addr = res->start + MCPDM_REG_UP_DATA; - - mcpdm->dma_data[0].filter_data = "dn_link"; - mcpdm->dma_data[1].filter_data = "up_link"; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); - mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(mcpdm->io_base)) - return PTR_ERR(mcpdm->io_base); - - mcpdm->irq = platform_get_irq(pdev, 0); - if (mcpdm->irq < 0) - return mcpdm->irq; - - mcpdm->dev = &pdev->dev; - - ret = devm_snd_soc_register_component(&pdev->dev, - &omap_mcpdm_component, - &omap_mcpdm_dai, 1); - if (ret) - return ret; - - return sdma_pcm_platform_register(&pdev->dev, "dn_link", "up_link"); -} - -static const struct of_device_id omap_mcpdm_of_match[] = { - { .compatible = "ti,omap4-mcpdm", }, - { } -}; -MODULE_DEVICE_TABLE(of, omap_mcpdm_of_match); - -static struct platform_driver asoc_mcpdm_driver = { - .driver = { - .name = "omap-mcpdm", - .of_match_table = omap_mcpdm_of_match, - }, - - .probe = asoc_mcpdm_probe, -}; - -module_platform_driver(asoc_mcpdm_driver); - -MODULE_ALIAS("platform:omap-mcpdm"); -MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); -MODULE_DESCRIPTION("OMAP PDM SoC Interface"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/omap/omap-mcpdm.h deleted file mode 100644 index de8cf26595b1..000000000000 --- a/sound/soc/omap/omap-mcpdm.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * omap-mcpdm.h - * - * Copyright (C) 2009 - 2011 Texas Instruments - * - * Contact: Misael Lopez Cruz <misael.lopez@ti.com> - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __OMAP_MCPDM_H__ -#define __OMAP_MCPDM_H__ - -#define MCPDM_REG_REVISION 0x00 -#define MCPDM_REG_SYSCONFIG 0x10 -#define MCPDM_REG_IRQSTATUS_RAW 0x24 -#define MCPDM_REG_IRQSTATUS 0x28 -#define MCPDM_REG_IRQENABLE_SET 0x2C -#define MCPDM_REG_IRQENABLE_CLR 0x30 -#define MCPDM_REG_IRQWAKE_EN 0x34 -#define MCPDM_REG_DMAENABLE_SET 0x38 -#define MCPDM_REG_DMAENABLE_CLR 0x3C -#define MCPDM_REG_DMAWAKEEN 0x40 -#define MCPDM_REG_CTRL 0x44 -#define MCPDM_REG_DN_DATA 0x48 -#define MCPDM_REG_UP_DATA 0x4C -#define MCPDM_REG_FIFO_CTRL_DN 0x50 -#define MCPDM_REG_FIFO_CTRL_UP 0x54 -#define MCPDM_REG_DN_OFFSET 0x58 - -/* - * MCPDM_IRQ bit fields - * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR - */ - -#define MCPDM_DN_IRQ (1 << 0) -#define MCPDM_DN_IRQ_EMPTY (1 << 1) -#define MCPDM_DN_IRQ_ALMST_EMPTY (1 << 2) -#define MCPDM_DN_IRQ_FULL (1 << 3) - -#define MCPDM_UP_IRQ (1 << 8) -#define MCPDM_UP_IRQ_EMPTY (1 << 9) -#define MCPDM_UP_IRQ_ALMST_FULL (1 << 10) -#define MCPDM_UP_IRQ_FULL (1 << 11) - -#define MCPDM_DOWNLINK_IRQ_MASK 0x00F -#define MCPDM_UPLINK_IRQ_MASK 0xF00 - -/* - * MCPDM_DMAENABLE bit fields - */ - -#define MCPDM_DMA_DN_ENABLE (1 << 0) -#define MCPDM_DMA_UP_ENABLE (1 << 1) - -/* - * MCPDM_CTRL bit fields - */ - -#define MCPDM_PDM_UPLINK_EN(x) (1 << (x - 1)) /* ch1 is at bit 0 */ -#define MCPDM_PDM_DOWNLINK_EN(x) (1 << (x + 2)) /* ch1 is at bit 3 */ -#define MCPDM_PDMOUTFORMAT (1 << 8) -#define MCPDM_CMD_INT (1 << 9) -#define MCPDM_STATUS_INT (1 << 10) -#define MCPDM_SW_UP_RST (1 << 11) -#define MCPDM_SW_DN_RST (1 << 12) -#define MCPDM_WD_EN (1 << 14) -#define MCPDM_PDM_UP_MASK 0x7 -#define MCPDM_PDM_DN_MASK (0x1f << 3) - - -#define MCPDM_PDMOUTFORMAT_LJUST (0 << 8) -#define MCPDM_PDMOUTFORMAT_RJUST (1 << 8) - -/* - * MCPDM_FIFO_CTRL bit fields - */ - -#define MCPDM_UP_THRES_MAX 0xF -#define MCPDM_DN_THRES_MAX 0xF - -/* - * MCPDM_DN_OFFSET bit fields - */ - -#define MCPDM_DN_OFST_RX1_EN (1 << 0) -#define MCPDM_DNOFST_RX1(x) ((x & 0x1f) << 1) -#define MCPDM_DN_OFST_RX2_EN (1 << 8) -#define MCPDM_DNOFST_RX2(x) ((x & 0x1f) << 9) - -void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd, - u8 rx1, u8 rx2); - -#endif /* End of __OMAP_MCPDM_H__ */ diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c deleted file mode 100644 index cccc316743fa..000000000000 --- a/sound/soc/omap/omap-twl4030.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * omap-twl4030.c -- SoC audio for TI SoC based boards with twl4030 codec - * - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com - * All rights reserved. - * - * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> - * - * This driver replaces the following machine drivers: - * omap3beagle (Author: Steve Sakoman <steve@sakoman.com>) - * omap3evm (Author: Anuj Aggarwal <anuj.aggarwal@ti.com>) - * overo (Author: Steve Sakoman <steve@sakoman.com>) - * igep0020 (Author: Enric Balletbo i Serra <eballetbo@iseebcn.com>) - * zoom2 (Author: Misael Lopez Cruz <misael.lopez@ti.com>) - * sdp3430 (Author: Misael Lopez Cruz <misael.lopez@ti.com>) - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/platform_device.h> -#include <linux/platform_data/omap-twl4030.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/jack.h> - -#include "omap-mcbsp.h" - -struct omap_twl4030 { - int jack_detect; /* board can detect jack events */ - struct snd_soc_jack hs_jack; -}; - -static int omap_twl4030_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - unsigned int fmt; - - switch (params_channels(params)) { - case 2: /* Stereo I2S mode */ - fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; - break; - case 4: /* Four channel TDM mode */ - fmt = SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBM_CFM; - break; - default: - return -EINVAL; - } - - return snd_soc_runtime_set_dai_fmt(rtd, fmt); -} - -static const struct snd_soc_ops omap_twl4030_ops = { - .hw_params = omap_twl4030_hw_params, -}; - -static const struct snd_soc_dapm_widget dapm_widgets[] = { - SND_SOC_DAPM_SPK("Earpiece Spk", NULL), - SND_SOC_DAPM_SPK("Handsfree Spk", NULL), - SND_SOC_DAPM_HP("Headset Stereophone", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), - SND_SOC_DAPM_SPK("Carkit Spk", NULL), - - SND_SOC_DAPM_MIC("Main Mic", NULL), - SND_SOC_DAPM_MIC("Sub Mic", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Carkit Mic", NULL), - SND_SOC_DAPM_MIC("Digital0 Mic", NULL), - SND_SOC_DAPM_MIC("Digital1 Mic", NULL), - SND_SOC_DAPM_LINE("Line In", NULL), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - /* Headset Stereophone: HSOL, HSOR */ - {"Headset Stereophone", NULL, "HSOL"}, - {"Headset Stereophone", NULL, "HSOR"}, - /* External Speakers: HFL, HFR */ - {"Handsfree Spk", NULL, "HFL"}, - {"Handsfree Spk", NULL, "HFR"}, - /* External Speakers: PredrivL, PredrivR */ - {"Ext Spk", NULL, "PREDRIVEL"}, - {"Ext Spk", NULL, "PREDRIVER"}, - /* Carkit speakers: CARKITL, CARKITR */ - {"Carkit Spk", NULL, "CARKITL"}, - {"Carkit Spk", NULL, "CARKITR"}, - /* Earpiece */ - {"Earpiece Spk", NULL, "EARPIECE"}, - - /* External Mics: MAINMIC, SUBMIC with bias */ - {"MAINMIC", NULL, "Main Mic"}, - {"Main Mic", NULL, "Mic Bias 1"}, - {"SUBMIC", NULL, "Sub Mic"}, - {"Sub Mic", NULL, "Mic Bias 2"}, - /* Headset Mic: HSMIC with bias */ - {"HSMIC", NULL, "Headset Mic"}, - {"Headset Mic", NULL, "Headset Mic Bias"}, - /* Digital Mics: DIGIMIC0, DIGIMIC1 with bias */ - {"DIGIMIC0", NULL, "Digital0 Mic"}, - {"Digital0 Mic", NULL, "Mic Bias 1"}, - {"DIGIMIC1", NULL, "Digital1 Mic"}, - {"Digital1 Mic", NULL, "Mic Bias 2"}, - /* Carkit In: CARKITMIC */ - {"CARKITMIC", NULL, "Carkit Mic"}, - /* Aux In: AUXL, AUXR */ - {"AUXL", NULL, "Line In"}, - {"AUXR", NULL, "Line In"}, -}; - -/* Headset jack detection DAPM pins */ -static struct snd_soc_jack_pin hs_jack_pins[] = { - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Headset Stereophone", - .mask = SND_JACK_HEADPHONE, - }, -}; - -/* Headset jack detection gpios */ -static struct snd_soc_jack_gpio hs_jack_gpios[] = { - { - .name = "hsdet-gpio", - .report = SND_JACK_HEADSET, - .debounce_time = 200, - }, -}; - -static inline void twl4030_disconnect_pin(struct snd_soc_dapm_context *dapm, - int connected, char *pin) -{ - if (!connected) - snd_soc_dapm_disable_pin(dapm, pin); -} - -static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - struct snd_soc_dapm_context *dapm = &card->dapm; - struct omap_tw4030_pdata *pdata = dev_get_platdata(card->dev); - struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card); - int ret = 0; - - /* Headset jack detection only if it is supported */ - if (priv->jack_detect > 0) { - hs_jack_gpios[0].gpio = priv->jack_detect; - - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET, &priv->hs_jack, - hs_jack_pins, - ARRAY_SIZE(hs_jack_pins)); - if (ret) - return ret; - - ret = snd_soc_jack_add_gpios(&priv->hs_jack, - ARRAY_SIZE(hs_jack_gpios), - hs_jack_gpios); - if (ret) - return ret; - } - - /* - * NULL pdata means we booted with DT. In this case the routing is - * provided and the card is fully routed, no need to mark pins. - */ - if (!pdata || !pdata->custom_routing) - return ret; - - /* Disable not connected paths if not used */ - twl4030_disconnect_pin(dapm, pdata->has_ear, "Earpiece Spk"); - twl4030_disconnect_pin(dapm, pdata->has_hf, "Handsfree Spk"); - twl4030_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); - twl4030_disconnect_pin(dapm, pdata->has_predriv, "Ext Spk"); - twl4030_disconnect_pin(dapm, pdata->has_carkit, "Carkit Spk"); - - twl4030_disconnect_pin(dapm, pdata->has_mainmic, "Main Mic"); - twl4030_disconnect_pin(dapm, pdata->has_submic, "Sub Mic"); - twl4030_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); - twl4030_disconnect_pin(dapm, pdata->has_carkitmic, "Carkit Mic"); - twl4030_disconnect_pin(dapm, pdata->has_digimic0, "Digital0 Mic"); - twl4030_disconnect_pin(dapm, pdata->has_digimic1, "Digital1 Mic"); - twl4030_disconnect_pin(dapm, pdata->has_linein, "Line In"); - - return ret; -} - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link omap_twl4030_dai_links[] = { - { - .name = "TWL4030 HiFi", - .stream_name = "TWL4030 HiFi", - .cpu_dai_name = "omap-mcbsp.2", - .codec_dai_name = "twl4030-hifi", - .platform_name = "omap-mcbsp.2", - .codec_name = "twl4030-codec", - .init = omap_twl4030_init, - .ops = &omap_twl4030_ops, - }, - { - .name = "TWL4030 Voice", - .stream_name = "TWL4030 Voice", - .cpu_dai_name = "omap-mcbsp.3", - .codec_dai_name = "twl4030-voice", - .platform_name = "omap-mcbsp.3", - .codec_name = "twl4030-codec", - .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBM_CFM, - }, -}; - -/* Audio machine driver */ -static struct snd_soc_card omap_twl4030_card = { - .owner = THIS_MODULE, - .dai_link = omap_twl4030_dai_links, - .num_links = ARRAY_SIZE(omap_twl4030_dai_links), - - .dapm_widgets = dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(dapm_widgets), - .dapm_routes = audio_map, - .num_dapm_routes = ARRAY_SIZE(audio_map), -}; - -static int omap_twl4030_probe(struct platform_device *pdev) -{ - struct omap_tw4030_pdata *pdata = dev_get_platdata(&pdev->dev); - struct device_node *node = pdev->dev.of_node; - struct snd_soc_card *card = &omap_twl4030_card; - struct omap_twl4030 *priv; - int ret = 0; - - card->dev = &pdev->dev; - - priv = devm_kzalloc(&pdev->dev, sizeof(struct omap_twl4030), GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; - - if (node) { - struct device_node *dai_node; - struct property *prop; - - if (snd_soc_of_parse_card_name(card, "ti,model")) { - dev_err(&pdev->dev, "Card name is not provided\n"); - return -ENODEV; - } - - dai_node = of_parse_phandle(node, "ti,mcbsp", 0); - if (!dai_node) { - dev_err(&pdev->dev, "McBSP node is not provided\n"); - return -EINVAL; - } - omap_twl4030_dai_links[0].cpu_dai_name = NULL; - omap_twl4030_dai_links[0].cpu_of_node = dai_node; - - omap_twl4030_dai_links[0].platform_name = NULL; - omap_twl4030_dai_links[0].platform_of_node = dai_node; - - dai_node = of_parse_phandle(node, "ti,mcbsp-voice", 0); - if (!dai_node) { - card->num_links = 1; - } else { - omap_twl4030_dai_links[1].cpu_dai_name = NULL; - omap_twl4030_dai_links[1].cpu_of_node = dai_node; - - omap_twl4030_dai_links[1].platform_name = NULL; - omap_twl4030_dai_links[1].platform_of_node = dai_node; - } - - priv->jack_detect = of_get_named_gpio(node, - "ti,jack-det-gpio", 0); - - /* Optional: audio routing can be provided */ - prop = of_find_property(node, "ti,audio-routing", NULL); - if (prop) { - ret = snd_soc_of_parse_audio_routing(card, - "ti,audio-routing"); - if (ret) - return ret; - - card->fully_routed = 1; - } - } else if (pdata) { - if (pdata->card_name) { - card->name = pdata->card_name; - } else { - dev_err(&pdev->dev, "Card name is not provided\n"); - return -ENODEV; - } - - if (!pdata->voice_connected) - card->num_links = 1; - - priv->jack_detect = pdata->jack_detect; - } else { - dev_err(&pdev->dev, "Missing pdata\n"); - return -ENODEV; - } - - snd_soc_card_set_drvdata(card, priv); - ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { - dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n", - ret); - return ret; - } - - return 0; -} - -static const struct of_device_id omap_twl4030_of_match[] = { - {.compatible = "ti,omap-twl4030", }, - { }, -}; -MODULE_DEVICE_TABLE(of, omap_twl4030_of_match); - -static struct platform_driver omap_twl4030_driver = { - .driver = { - .name = "omap-twl4030", - .pm = &snd_soc_pm_ops, - .of_match_table = omap_twl4030_of_match, - }, - .probe = omap_twl4030_probe, -}; - -module_platform_driver(omap_twl4030_driver); - -MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); -MODULE_DESCRIPTION("ALSA SoC for TI SoC based boards with twl4030 codec"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:omap-twl4030"); diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c deleted file mode 100644 index 4e3de712159c..000000000000 --- a/sound/soc/omap/omap3pandora.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * omap3pandora.c -- SoC audio for Pandora Handheld Console - * - * Author: Gražvydas Ignotas <notasas@gmail.com> - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/gpio.h> -#include <linux/delay.h> -#include <linux/regulator/consumer.h> -#include <linux/module.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> - -#include <asm/mach-types.h> -#include <linux/platform_data/asoc-ti-mcbsp.h> - -#include "omap-mcbsp.h" - -#define OMAP3_PANDORA_DAC_POWER_GPIO 118 -#define OMAP3_PANDORA_AMP_POWER_GPIO 14 - -#define PREFIX "ASoC omap3pandora: " - -static struct regulator *omap3pandora_dac_reg; - -static int omap3pandora_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->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret; - - /* Set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, - SND_SOC_CLOCK_IN); - if (ret < 0) { - pr_err(PREFIX "can't set codec system clock\n"); - return ret; - } - - /* Set McBSP clock to external */ - ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT, - 256 * params_rate(params), - SND_SOC_CLOCK_IN); - if (ret < 0) { - pr_err(PREFIX "can't set cpu system clock\n"); - return ret; - } - - ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, 8); - if (ret < 0) { - pr_err(PREFIX "can't set SRG clock divider\n"); - return ret; - } - - return 0; -} - -static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - int ret; - - /* - * The PCM1773 DAC datasheet requires 1ms delay between switching - * VCC power on/off and /PD pin high/low - */ - if (SND_SOC_DAPM_EVENT_ON(event)) { - ret = regulator_enable(omap3pandora_dac_reg); - if (ret) { - dev_err(w->dapm->dev, "Failed to power DAC: %d\n", ret); - return ret; - } - mdelay(1); - gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1); - } else { - gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0); - mdelay(1); - regulator_disable(omap3pandora_dac_reg); - } - - return 0; -} - -static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - if (SND_SOC_DAPM_EVENT_ON(event)) - gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1); - else - gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0); - - return 0; -} - -/* - * Audio paths on Pandora board: - * - * |O| ---> PCM DAC +-> AMP -> Headphone Jack - * |M| A +--------> Line Out - * |A| <~~clk~~+ - * |P| <--- TWL4030 <--------- Line In and MICs - */ -static const struct snd_soc_dapm_widget omap3pandora_dapm_widgets[] = { - SND_SOC_DAPM_DAC_E("PCM DAC", "HiFi Playback", SND_SOC_NOPM, - 0, 0, omap3pandora_dac_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM, - 0, 0, NULL, 0, omap3pandora_hp_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_LINE("Line Out", NULL), - - SND_SOC_DAPM_MIC("Mic (internal)", NULL), - SND_SOC_DAPM_MIC("Mic (external)", NULL), - SND_SOC_DAPM_LINE("Line In", NULL), -}; - -static const struct snd_soc_dapm_route omap3pandora_map[] = { - {"PCM DAC", NULL, "APLL Enable"}, - {"Headphone Amplifier", NULL, "PCM DAC"}, - {"Line Out", NULL, "PCM DAC"}, - {"Headphone Jack", NULL, "Headphone Amplifier"}, - - {"AUXL", NULL, "Line In"}, - {"AUXR", NULL, "Line In"}, - - {"MAINMIC", NULL, "Mic (internal)"}, - {"Mic (internal)", NULL, "Mic Bias 1"}, - - {"SUBMIC", NULL, "Mic (external)"}, - {"Mic (external)", NULL, "Mic Bias 2"}, -}; - -static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm = &rtd->card->dapm; - - /* All TWL4030 output pins are floating */ - snd_soc_dapm_nc_pin(dapm, "EARPIECE"); - snd_soc_dapm_nc_pin(dapm, "PREDRIVEL"); - snd_soc_dapm_nc_pin(dapm, "PREDRIVER"); - snd_soc_dapm_nc_pin(dapm, "HSOL"); - snd_soc_dapm_nc_pin(dapm, "HSOR"); - snd_soc_dapm_nc_pin(dapm, "CARKITL"); - snd_soc_dapm_nc_pin(dapm, "CARKITR"); - snd_soc_dapm_nc_pin(dapm, "HFL"); - snd_soc_dapm_nc_pin(dapm, "HFR"); - snd_soc_dapm_nc_pin(dapm, "VIBRA"); - - return 0; -} - -static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm = &rtd->card->dapm; - - /* Not comnnected */ - snd_soc_dapm_nc_pin(dapm, "HSMIC"); - snd_soc_dapm_nc_pin(dapm, "CARKITMIC"); - snd_soc_dapm_nc_pin(dapm, "DIGIMIC0"); - snd_soc_dapm_nc_pin(dapm, "DIGIMIC1"); - - return 0; -} - -static const struct snd_soc_ops omap3pandora_ops = { - .hw_params = omap3pandora_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link omap3pandora_dai[] = { - { - .name = "PCM1773", - .stream_name = "HiFi Out", - .cpu_dai_name = "omap-mcbsp.2", - .codec_dai_name = "twl4030-hifi", - .platform_name = "omap-mcbsp.2", - .codec_name = "twl4030-codec", - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - .ops = &omap3pandora_ops, - .init = omap3pandora_out_init, - }, { - .name = "TWL4030", - .stream_name = "Line/Mic In", - .cpu_dai_name = "omap-mcbsp.4", - .codec_dai_name = "twl4030-hifi", - .platform_name = "omap-mcbsp.4", - .codec_name = "twl4030-codec", - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - .ops = &omap3pandora_ops, - .init = omap3pandora_in_init, - } -}; - -/* SoC card */ -static struct snd_soc_card snd_soc_card_omap3pandora = { - .name = "omap3pandora", - .owner = THIS_MODULE, - .dai_link = omap3pandora_dai, - .num_links = ARRAY_SIZE(omap3pandora_dai), - - .dapm_widgets = omap3pandora_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(omap3pandora_dapm_widgets), - .dapm_routes = omap3pandora_map, - .num_dapm_routes = ARRAY_SIZE(omap3pandora_map), -}; - -static struct platform_device *omap3pandora_snd_device; - -static int __init omap3pandora_soc_init(void) -{ - int ret; - - if (!machine_is_omap3_pandora()) - return -ENODEV; - - pr_info("OMAP3 Pandora SoC init\n"); - - ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power"); - if (ret) { - pr_err(PREFIX "Failed to get DAC power GPIO\n"); - return ret; - } - - ret = gpio_direction_output(OMAP3_PANDORA_DAC_POWER_GPIO, 0); - if (ret) { - pr_err(PREFIX "Failed to set DAC power GPIO direction\n"); - goto fail0; - } - - ret = gpio_request(OMAP3_PANDORA_AMP_POWER_GPIO, "amp_power"); - if (ret) { - pr_err(PREFIX "Failed to get amp power GPIO\n"); - goto fail0; - } - - ret = gpio_direction_output(OMAP3_PANDORA_AMP_POWER_GPIO, 0); - if (ret) { - pr_err(PREFIX "Failed to set amp power GPIO direction\n"); - goto fail1; - } - - omap3pandora_snd_device = platform_device_alloc("soc-audio", -1); - if (omap3pandora_snd_device == NULL) { - pr_err(PREFIX "Platform device allocation failed\n"); - ret = -ENOMEM; - goto fail1; - } - - platform_set_drvdata(omap3pandora_snd_device, &snd_soc_card_omap3pandora); - - ret = platform_device_add(omap3pandora_snd_device); - if (ret) { - pr_err(PREFIX "Unable to add platform device\n"); - goto fail2; - } - - omap3pandora_dac_reg = regulator_get(&omap3pandora_snd_device->dev, "vcc"); - if (IS_ERR(omap3pandora_dac_reg)) { - pr_err(PREFIX "Failed to get DAC regulator from %s: %ld\n", - dev_name(&omap3pandora_snd_device->dev), - PTR_ERR(omap3pandora_dac_reg)); - ret = PTR_ERR(omap3pandora_dac_reg); - goto fail3; - } - - return 0; - -fail3: - platform_device_del(omap3pandora_snd_device); -fail2: - platform_device_put(omap3pandora_snd_device); -fail1: - gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO); -fail0: - gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO); - return ret; -} -module_init(omap3pandora_soc_init); - -static void __exit omap3pandora_soc_exit(void) -{ - regulator_put(omap3pandora_dac_reg); - platform_device_unregister(omap3pandora_snd_device); - gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO); - gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO); -} -module_exit(omap3pandora_soc_exit); - -MODULE_AUTHOR("Grazvydas Ignotas <notasas@gmail.com>"); -MODULE_DESCRIPTION("ALSA SoC OMAP3 Pandora"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c deleted file mode 100644 index e4096779ca05..000000000000 --- a/sound/soc/omap/osk5912.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * osk5912.c -- SoC audio for OSK 5912 - * - * Copyright (C) 2008 Mistral Solutions - * - * Contact: Arun KS <arunks@mistralsolutions.com> - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> - -#include <asm/mach-types.h> -#include <linux/gpio.h> -#include <linux/module.h> -#include <linux/platform_data/asoc-ti-mcbsp.h> - -#include "omap-mcbsp.h" -#include "../codecs/tlv320aic23.h" - -#define CODEC_CLOCK 12000000 - -static struct clk *tlv320aic23_mclk; - -static int osk_startup(struct snd_pcm_substream *substream) -{ - return clk_enable(tlv320aic23_mclk); -} - -static void osk_shutdown(struct snd_pcm_substream *substream) -{ - clk_disable(tlv320aic23_mclk); -} - -static int osk_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->codec_dai; - int err; - - /* Set the codec system clock for DAC and ADC */ - err = - snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN); - - if (err < 0) { - printk(KERN_ERR "can't set codec system clock\n"); - return err; - } - - return err; -} - -static const struct snd_soc_ops osk_ops = { - .startup = osk_startup, - .hw_params = osk_hw_params, - .shutdown = osk_shutdown, -}; - -static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_LINE("Line In", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - {"Headphone Jack", NULL, "LHPOUT"}, - {"Headphone Jack", NULL, "RHPOUT"}, - - {"LLINEIN", NULL, "Line In"}, - {"RLINEIN", NULL, "Line In"}, - - {"MICIN", NULL, "Mic Jack"}, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link osk_dai = { - .name = "TLV320AIC23", - .stream_name = "AIC23", - .cpu_dai_name = "omap-mcbsp.1", - .codec_dai_name = "tlv320aic23-hifi", - .platform_name = "omap-mcbsp.1", - .codec_name = "tlv320aic23-codec", - .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, - .ops = &osk_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_card_osk = { - .name = "OSK5912", - .owner = THIS_MODULE, - .dai_link = &osk_dai, - .num_links = 1, - - .dapm_widgets = tlv320aic23_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets), - .dapm_routes = audio_map, - .num_dapm_routes = ARRAY_SIZE(audio_map), -}; - -static struct platform_device *osk_snd_device; - -static int __init osk_soc_init(void) -{ - int err; - u32 curRate; - struct device *dev; - - if (!(machine_is_omap_osk())) - return -ENODEV; - - osk_snd_device = platform_device_alloc("soc-audio", -1); - if (!osk_snd_device) - return -ENOMEM; - - platform_set_drvdata(osk_snd_device, &snd_soc_card_osk); - err = platform_device_add(osk_snd_device); - if (err) - goto err1; - - dev = &osk_snd_device->dev; - - tlv320aic23_mclk = clk_get(dev, "mclk"); - if (IS_ERR(tlv320aic23_mclk)) { - printk(KERN_ERR "Could not get mclk clock\n"); - err = PTR_ERR(tlv320aic23_mclk); - goto err2; - } - - /* - * Configure 12 MHz output on MCLK. - */ - curRate = (uint) clk_get_rate(tlv320aic23_mclk); - if (curRate != CODEC_CLOCK) { - if (clk_set_rate(tlv320aic23_mclk, CODEC_CLOCK)) { - printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n"); - err = -ECANCELED; - goto err3; - } - } - - printk(KERN_INFO "MCLK = %d [%d]\n", - (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK); - - return 0; - -err3: - clk_put(tlv320aic23_mclk); -err2: - platform_device_del(osk_snd_device); -err1: - platform_device_put(osk_snd_device); - - return err; - -} - -static void __exit osk_soc_exit(void) -{ - clk_put(tlv320aic23_mclk); - platform_device_unregister(osk_snd_device); -} - -module_init(osk_soc_init); -module_exit(osk_soc_exit); - -MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); -MODULE_DESCRIPTION("ALSA SoC OSK 5912"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c deleted file mode 100644 index 57448bd5ad77..000000000000 --- a/sound/soc/omap/rx51.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - * rx51.c -- SoC audio for Nokia RX-51 - * - * Copyright (C) 2008 - 2009 Nokia Corporation - * - * Contact: Peter Ujfalusi <peter.ujfalusi@ti.com> - * Eduardo Valentin <eduardo.valentin@nokia.com> - * Jarkko Nikula <jarkko.nikula@bitmer.com> - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/delay.h> -#include <linux/gpio.h> -#include <linux/platform_device.h> -#include <linux/gpio/consumer.h> -#include <linux/module.h> -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <linux/platform_data/asoc-ti-mcbsp.h> - -#include <asm/mach-types.h> - -#include "omap-mcbsp.h" - -enum { - RX51_JACK_DISABLED, - RX51_JACK_TVOUT, /* tv-out with stereo output */ - RX51_JACK_HP, /* headphone: stereo output, no mic */ - RX51_JACK_HS, /* headset: stereo output with mic */ -}; - -struct rx51_audio_pdata { - struct gpio_desc *tvout_selection_gpio; - struct gpio_desc *jack_detection_gpio; - struct gpio_desc *eci_sw_gpio; - struct gpio_desc *speaker_amp_gpio; -}; - -static int rx51_spk_func; -static int rx51_dmic_func; -static int rx51_jack_func; - -static void rx51_ext_control(struct snd_soc_dapm_context *dapm) -{ - struct snd_soc_card *card = dapm->card; - struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card); - int hp = 0, hs = 0, tvout = 0; - - switch (rx51_jack_func) { - case RX51_JACK_TVOUT: - tvout = 1; - hp = 1; - break; - case RX51_JACK_HS: - hs = 1; - case RX51_JACK_HP: - hp = 1; - break; - } - - snd_soc_dapm_mutex_lock(dapm); - - if (rx51_spk_func) - snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); - else - snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); - if (rx51_dmic_func) - snd_soc_dapm_enable_pin_unlocked(dapm, "DMic"); - else - snd_soc_dapm_disable_pin_unlocked(dapm, "DMic"); - if (hp) - snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); - else - snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); - if (hs) - snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic"); - else - snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic"); - - gpiod_set_value(pdata->tvout_selection_gpio, tvout); - - snd_soc_dapm_sync_unlocked(dapm); - - snd_soc_dapm_mutex_unlock(dapm); -} - -static int rx51_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_card *card = rtd->card; - - snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2); - rx51_ext_control(&card->dapm); - - return 0; -} - -static int rx51_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->codec_dai; - - /* Set the codec system clock for DAC and ADC */ - return snd_soc_dai_set_sysclk(codec_dai, 0, 19200000, - SND_SOC_CLOCK_IN); -} - -static const struct snd_soc_ops rx51_ops = { - .startup = rx51_startup, - .hw_params = rx51_hw_params, -}; - -static int rx51_get_spk(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = rx51_spk_func; - - return 0; -} - -static int rx51_set_spk(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); - - if (rx51_spk_func == ucontrol->value.enumerated.item[0]) - return 0; - - rx51_spk_func = ucontrol->value.enumerated.item[0]; - rx51_ext_control(&card->dapm); - - return 1; -} - -static int rx51_spk_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card); - - gpiod_set_raw_value_cansleep(pdata->speaker_amp_gpio, - !!SND_SOC_DAPM_EVENT_ON(event)); - - return 0; -} - -static int rx51_get_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = rx51_dmic_func; - - return 0; -} - -static int rx51_set_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); - - if (rx51_dmic_func == ucontrol->value.enumerated.item[0]) - return 0; - - rx51_dmic_func = ucontrol->value.enumerated.item[0]; - rx51_ext_control(&card->dapm); - - return 1; -} - -static int rx51_get_jack(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = rx51_jack_func; - - return 0; -} - -static int rx51_set_jack(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); - - if (rx51_jack_func == ucontrol->value.enumerated.item[0]) - return 0; - - rx51_jack_func = ucontrol->value.enumerated.item[0]; - rx51_ext_control(&card->dapm); - - return 1; -} - -static struct snd_soc_jack rx51_av_jack; - -static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = { - { - .name = "avdet-gpio", - .report = SND_JACK_HEADSET, - .invert = 1, - .debounce_time = 200, - }, -}; - -static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { - SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event), - SND_SOC_DAPM_MIC("DMic", NULL), - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("HS Mic", NULL), - SND_SOC_DAPM_LINE("FM Transmitter", NULL), - SND_SOC_DAPM_SPK("Earphone", NULL), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - {"Ext Spk", NULL, "HPLOUT"}, - {"Ext Spk", NULL, "HPROUT"}, - {"Ext Spk", NULL, "HPLCOM"}, - {"Ext Spk", NULL, "HPRCOM"}, - {"FM Transmitter", NULL, "LLOUT"}, - {"FM Transmitter", NULL, "RLOUT"}, - - {"Headphone Jack", NULL, "TPA6130A2 HPLEFT"}, - {"Headphone Jack", NULL, "TPA6130A2 HPRIGHT"}, - {"TPA6130A2 LEFTIN", NULL, "LLOUT"}, - {"TPA6130A2 RIGHTIN", NULL, "RLOUT"}, - - {"DMic Rate 64", NULL, "DMic"}, - {"DMic", NULL, "Mic Bias"}, - - {"b LINE2R", NULL, "MONO_LOUT"}, - {"Earphone", NULL, "b HPLOUT"}, - - {"LINE1L", NULL, "HS Mic"}, - {"HS Mic", NULL, "b Mic Bias"}, -}; - -static const char * const spk_function[] = {"Off", "On"}; -static const char * const input_function[] = {"ADC", "Digital Mic"}; -static const char * const jack_function[] = { - "Off", "TV-OUT", "Headphone", "Headset" -}; - -static const struct soc_enum rx51_enum[] = { - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), -}; - -static const struct snd_kcontrol_new aic34_rx51_controls[] = { - SOC_ENUM_EXT("Speaker Function", rx51_enum[0], - rx51_get_spk, rx51_set_spk), - SOC_ENUM_EXT("Input Select", rx51_enum[1], - rx51_get_input, rx51_set_input), - SOC_ENUM_EXT("Jack Function", rx51_enum[2], - rx51_get_jack, rx51_set_jack), - SOC_DAPM_PIN_SWITCH("FM Transmitter"), - SOC_DAPM_PIN_SWITCH("Earphone"), -}; - -static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card); - int err; - - snd_soc_limit_volume(card, "TPA6130A2 Headphone Playback Volume", 42); - - err = omap_mcbsp_st_add_controls(rtd, 2); - if (err < 0) { - dev_err(card->dev, "Failed to add MCBSP controls\n"); - return err; - } - - /* AV jack detection */ - err = snd_soc_card_jack_new(rtd->card, "AV Jack", - SND_JACK_HEADSET | SND_JACK_VIDEOOUT, - &rx51_av_jack, NULL, 0); - if (err) { - dev_err(card->dev, "Failed to add AV Jack\n"); - return err; - } - - /* prepare gpio for snd_soc_jack_add_gpios */ - rx51_av_jack_gpios[0].gpio = desc_to_gpio(pdata->jack_detection_gpio); - devm_gpiod_put(card->dev, pdata->jack_detection_gpio); - - err = snd_soc_jack_add_gpios(&rx51_av_jack, - ARRAY_SIZE(rx51_av_jack_gpios), - rx51_av_jack_gpios); - if (err) { - dev_err(card->dev, "Failed to add GPIOs\n"); - return err; - } - - return err; -} - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link rx51_dai[] = { - { - .name = "TLV320AIC34", - .stream_name = "AIC34", - .cpu_dai_name = "omap-mcbsp.2", - .codec_dai_name = "tlv320aic3x-hifi", - .platform_name = "omap-mcbsp.2", - .codec_name = "tlv320aic3x-codec.2-0018", - .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBM_CFM, - .init = rx51_aic34_init, - .ops = &rx51_ops, - }, -}; - -static struct snd_soc_aux_dev rx51_aux_dev[] = { - { - .name = "TLV320AIC34b", - .codec_name = "tlv320aic3x-codec.2-0019", - }, - { - .name = "TPA61320A2", - .codec_name = "tpa6130a2.2-0060", - }, -}; - -static struct snd_soc_codec_conf rx51_codec_conf[] = { - { - .dev_name = "tlv320aic3x-codec.2-0019", - .name_prefix = "b", - }, - { - .dev_name = "tpa6130a2.2-0060", - .name_prefix = "TPA6130A2", - }, -}; - -/* Audio card */ -static struct snd_soc_card rx51_sound_card = { - .name = "RX-51", - .owner = THIS_MODULE, - .dai_link = rx51_dai, - .num_links = ARRAY_SIZE(rx51_dai), - .aux_dev = rx51_aux_dev, - .num_aux_devs = ARRAY_SIZE(rx51_aux_dev), - .codec_conf = rx51_codec_conf, - .num_configs = ARRAY_SIZE(rx51_codec_conf), - .fully_routed = true, - - .controls = aic34_rx51_controls, - .num_controls = ARRAY_SIZE(aic34_rx51_controls), - .dapm_widgets = aic34_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(aic34_dapm_widgets), - .dapm_routes = audio_map, - .num_dapm_routes = ARRAY_SIZE(audio_map), -}; - -static int rx51_soc_probe(struct platform_device *pdev) -{ - struct rx51_audio_pdata *pdata; - struct device_node *np = pdev->dev.of_node; - struct snd_soc_card *card = &rx51_sound_card; - int err; - - if (!machine_is_nokia_rx51() && !of_machine_is_compatible("nokia,omap3-n900")) - return -ENODEV; - - card->dev = &pdev->dev; - - if (np) { - struct device_node *dai_node; - - dai_node = of_parse_phandle(np, "nokia,cpu-dai", 0); - if (!dai_node) { - dev_err(&pdev->dev, "McBSP node is not provided\n"); - return -EINVAL; - } - rx51_dai[0].cpu_dai_name = NULL; - rx51_dai[0].platform_name = NULL; - rx51_dai[0].cpu_of_node = dai_node; - rx51_dai[0].platform_of_node = dai_node; - - dai_node = of_parse_phandle(np, "nokia,audio-codec", 0); - if (!dai_node) { - dev_err(&pdev->dev, "Codec node is not provided\n"); - return -EINVAL; - } - rx51_dai[0].codec_name = NULL; - rx51_dai[0].codec_of_node = dai_node; - - dai_node = of_parse_phandle(np, "nokia,audio-codec", 1); - if (!dai_node) { - dev_err(&pdev->dev, "Auxiliary Codec node is not provided\n"); - return -EINVAL; - } - rx51_aux_dev[0].codec_name = NULL; - rx51_aux_dev[0].codec_of_node = dai_node; - rx51_codec_conf[0].dev_name = NULL; - rx51_codec_conf[0].of_node = dai_node; - - dai_node = of_parse_phandle(np, "nokia,headphone-amplifier", 0); - if (!dai_node) { - dev_err(&pdev->dev, "Headphone amplifier node is not provided\n"); - return -EINVAL; - } - rx51_aux_dev[1].codec_name = NULL; - rx51_aux_dev[1].codec_of_node = dai_node; - rx51_codec_conf[1].dev_name = NULL; - rx51_codec_conf[1].of_node = dai_node; - } - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (pdata == NULL) - return -ENOMEM; - - snd_soc_card_set_drvdata(card, pdata); - - pdata->tvout_selection_gpio = devm_gpiod_get(card->dev, - "tvout-selection", - GPIOD_OUT_LOW); - if (IS_ERR(pdata->tvout_selection_gpio)) { - dev_err(card->dev, "could not get tvout selection gpio\n"); - return PTR_ERR(pdata->tvout_selection_gpio); - } - - pdata->jack_detection_gpio = devm_gpiod_get(card->dev, - "jack-detection", - GPIOD_ASIS); - if (IS_ERR(pdata->jack_detection_gpio)) { - dev_err(card->dev, "could not get jack detection gpio\n"); - return PTR_ERR(pdata->jack_detection_gpio); - } - - pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch", - GPIOD_OUT_HIGH); - if (IS_ERR(pdata->eci_sw_gpio)) { - dev_err(card->dev, "could not get eci switch gpio\n"); - return PTR_ERR(pdata->eci_sw_gpio); - } - - pdata->speaker_amp_gpio = devm_gpiod_get(card->dev, - "speaker-amplifier", - GPIOD_OUT_LOW); - if (IS_ERR(pdata->speaker_amp_gpio)) { - dev_err(card->dev, "could not get speaker enable gpio\n"); - return PTR_ERR(pdata->speaker_amp_gpio); - } - - err = devm_snd_soc_register_card(card->dev, card); - if (err) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", err); - return err; - } - - return 0; -} - -#if defined(CONFIG_OF) -static const struct of_device_id rx51_audio_of_match[] = { - { .compatible = "nokia,n900-audio", }, - {}, -}; -MODULE_DEVICE_TABLE(of, rx51_audio_of_match); -#endif - -static struct platform_driver rx51_soc_driver = { - .driver = { - .name = "rx51-audio", - .of_match_table = of_match_ptr(rx51_audio_of_match), - }, - .probe = rx51_soc_probe, -}; - -module_platform_driver(rx51_soc_driver); - -MODULE_AUTHOR("Nokia Corporation"); -MODULE_DESCRIPTION("ALSA SoC Nokia RX-51"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:rx51-audio"); diff --git a/sound/soc/omap/sdma-pcm.c b/sound/soc/omap/sdma-pcm.c deleted file mode 100644 index 21a9c2499d48..000000000000 --- a/sound/soc/omap/sdma-pcm.c +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com - * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> - */ - -#include <linux/device.h> -#include <linux/module.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/dmaengine_pcm.h> -#include <linux/omap-dmaengine.h> - -#include "sdma-pcm.h" - -static const struct snd_pcm_hardware sdma_pcm_hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP | - SNDRV_PCM_INFO_INTERLEAVED, - .period_bytes_min = 32, - .period_bytes_max = 64 * 1024, - .buffer_bytes_max = 128 * 1024, - .periods_min = 2, - .periods_max = 255, -}; - -static const struct snd_dmaengine_pcm_config sdma_dmaengine_pcm_config = { - .pcm_hardware = &sdma_pcm_hardware, - .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, - .compat_filter_fn = omap_dma_filter_fn, - .prealloc_buffer_size = 128 * 1024, -}; - -int sdma_pcm_platform_register(struct device *dev, - char *txdmachan, char *rxdmachan) -{ - struct snd_dmaengine_pcm_config *config; - unsigned int flags = SND_DMAENGINE_PCM_FLAG_COMPAT; - - /* Standard names for the directions: 'tx' and 'rx' */ - if (!txdmachan && !rxdmachan) - return devm_snd_dmaengine_pcm_register(dev, - &sdma_dmaengine_pcm_config, - flags); - - config = devm_kzalloc(dev, sizeof(*config), GFP_KERNEL); - if (!config) - return -ENOMEM; - - *config = sdma_dmaengine_pcm_config; - - if (!txdmachan || !rxdmachan) { - /* One direction only PCM */ - flags |= SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX; - if (!txdmachan) { - txdmachan = rxdmachan; - rxdmachan = NULL; - } - } - - config->chan_names[0] = txdmachan; - config->chan_names[1] = rxdmachan; - - return devm_snd_dmaengine_pcm_register(dev, config, flags); -} -EXPORT_SYMBOL_GPL(sdma_pcm_platform_register); - -MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); -MODULE_DESCRIPTION("sDMA PCM ASoC platform driver"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/omap/sdma-pcm.h b/sound/soc/omap/sdma-pcm.h deleted file mode 100644 index 34a7f90b2587..000000000000 --- a/sound/soc/omap/sdma-pcm.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com - * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> - */ - -#ifndef __SDMA_PCM_H__ -#define __SDMA_PCM_H__ - -#if IS_ENABLED(CONFIG_SND_SDMA_SOC) -int sdma_pcm_platform_register(struct device *dev, - char *txdmachan, char *rxdmachan); -#else -static inline int sdma_pcm_platform_register(struct device *dev, - char *txdmachan, char *rxdmachan) -{ - return -ENODEV; -} -#endif /* CONFIG_SND_SDMA_SOC */ - -#endif /* __SDMA_PCM_H__ */ |