aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/omap
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/omap')
-rw-r--r--sound/soc/omap/Kconfig98
-rw-r--r--sound/soc/omap/Makefile25
-rw-r--r--sound/soc/omap/am3517evm.c30
-rw-r--r--sound/soc/omap/ams-delta.c235
-rw-r--r--sound/soc/omap/igep0020.c120
-rw-r--r--sound/soc/omap/mcbsp.c1101
-rw-r--r--sound/soc/omap/mcbsp.h354
-rw-r--r--sound/soc/omap/n810.c66
-rw-r--r--sound/soc/omap/omap-abe-twl6040.c370
-rw-r--r--sound/soc/omap/omap-dmic.c88
-rw-r--r--sound/soc/omap/omap-hdmi-card.c87
-rw-r--r--sound/soc/omap/omap-hdmi.c266
-rw-r--r--sound/soc/omap/omap-hdmi.h4
-rw-r--r--sound/soc/omap/omap-mcbsp.c544
-rw-r--r--sound/soc/omap/omap-mcbsp.h22
-rw-r--r--sound/soc/omap/omap-mcpdm.c199
-rw-r--r--sound/soc/omap/omap-pcm.c302
-rw-r--r--sound/soc/omap/omap-pcm.h38
-rw-r--r--sound/soc/omap/omap-twl4030.c390
-rw-r--r--sound/soc/omap/omap3beagle.c150
-rw-r--r--sound/soc/omap/omap3evm.c118
-rw-r--r--sound/soc/omap/omap3pandora.c58
-rw-r--r--sound/soc/omap/omap4-hdmi-card.c121
-rw-r--r--sound/soc/omap/osk5912.c8
-rw-r--r--sound/soc/omap/overo.c122
-rw-r--r--sound/soc/omap/rx51.c331
-rw-r--r--sound/soc/omap/sdp3430.c279
-rw-r--r--sound/soc/omap/sdp4430.c279
-rw-r--r--sound/soc/omap/zoom2.c219
29 files changed, 3451 insertions, 2573 deletions
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index fb1bf2581ef..d44463a7b0f 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -1,13 +1,13 @@
config SND_OMAP_SOC
tristate "SoC Audio for the Texas Instruments OMAP chips"
- depends on ARCH_OMAP
+ depends on (ARCH_OMAP && DMA_OMAP) || (ARM && COMPILE_TEST)
+ select SND_DMAENGINE_PCM
config SND_OMAP_SOC_DMIC
tristate
config SND_OMAP_SOC_MCBSP
tristate
- select OMAP_MCBSP
config SND_OMAP_SOC_MCPDM
tristate
@@ -26,18 +26,18 @@ config SND_OMAP_SOC_N810
config SND_OMAP_SOC_RX51
tristate "SoC Audio support for Nokia RX-51"
- depends on SND_OMAP_SOC && MACH_NOKIA_RX51
- select OMAP_MCBSP
+ depends on SND_OMAP_SOC && ARM && (MACH_NOKIA_RX51 || COMPILE_TEST) && 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 RX-51
hardware. This is also known as Nokia N900 product.
config SND_OMAP_SOC_AMS_DELTA
tristate "SoC Audio support for Amstrad E3 (Delta) videophone"
- depends on SND_OMAP_SOC && MACH_AMS_DELTA
+ depends on SND_OMAP_SOC && MACH_AMS_DELTA && TTY
select SND_OMAP_SOC_MCBSP
select SND_SOC_CX20442
help
@@ -58,60 +58,54 @@ config SND_OMAP_SOC_OSK5912
tristate "SoC Audio support for omap osk5912"
depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C
select SND_OMAP_SOC_MCBSP
- select SND_SOC_TLV320AIC23
+ select SND_SOC_TLV320AIC23_I2C
help
Say Y if you want to add support for SoC audio on osk5912.
-config SND_OMAP_SOC_OVERO
- tristate "SoC Audio support for Gumstix Overo and CompuLab CM-T35"
- depends on TWL4030_CORE && SND_OMAP_SOC && (MACH_OVERO || MACH_CM_T35)
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TWL4030
- help
- Say Y if you want to add support for SoC audio on the
- Gumstix Overo or CompuLab CM-T35
-
-config SND_OMAP_SOC_OMAP3EVM
- tristate "SoC Audio support for OMAP3EVM board"
- depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3EVM
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TWL4030
- help
- Say Y if you want to add support for SoC audio on the omap3evm board.
-
config SND_OMAP_SOC_AM3517EVM
tristate "SoC Audio support for OMAP3517 / AM3517 EVM"
depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C
select SND_OMAP_SOC_MCBSP
- select SND_SOC_TLV320AIC23
+ select SND_SOC_TLV320AIC23_I2C
help
Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517
EVM.
-config SND_OMAP_SOC_SDP3430
- tristate "SoC Audio support for Texas Instruments SDP3430"
- depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP
+config SND_OMAP_SOC_OMAP_TWL4030
+ tristate "SoC Audio support for TI SoC based boards with twl4030 codec"
+ depends on TWL4030_CORE && SND_OMAP_SOC
select SND_OMAP_SOC_MCBSP
select SND_SOC_TWL4030
help
- Say Y if you want to add support for SoC audio on Texas Instruments
- SDP3430.
-
-config SND_OMAP_SOC_SDP4430
- tristate "SoC Audio support for Texas Instruments SDP4430"
- depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_4430SDP
+ 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_OMAP_SOC && (ARCH_OMAP4 || COMPILE_TEST)
select SND_OMAP_SOC_DMIC
select SND_OMAP_SOC_MCPDM
select SND_SOC_TWL6040
select SND_SOC_DMIC
help
- Say Y if you want to add support for SoC audio on Texas Instruments
- SDP4430.
-
-config SND_OMAP_SOC_OMAP4_HDMI
- tristate "SoC Audio support for Texas Instruments OMAP4 HDMI"
- depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4
+ 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)
+
+config SND_OMAP_SOC_OMAP_HDMI
+ tristate "SoC Audio support for Texas Instruments OMAP HDMI"
+ depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS
select SND_OMAP_SOC_HDMI
+ select SND_SOC_HDMI_CODEC
+ select OMAP4_DSS_HDMI_AUDIO
help
Say Y if you want to add support for SoC HDMI audio on Texas Instruments
OMAP4 chips
@@ -123,29 +117,3 @@ config SND_OMAP_SOC_OMAP3_PANDORA
select SND_SOC_TWL4030
help
Say Y if you want to add support for SoC audio on the OMAP3 Pandora.
-
-config SND_OMAP_SOC_OMAP3_BEAGLE
- tristate "SoC Audio support for OMAP3 Beagle and Devkit8000"
- depends on TWL4030_CORE && SND_OMAP_SOC
- depends on (MACH_OMAP3_BEAGLE || MACH_DEVKIT8000)
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TWL4030
- help
- Say Y if you want to add support for SoC audio on the Beagleboard or
- the clone Devkit8000.
-
-config SND_OMAP_SOC_ZOOM2
- tristate "SoC Audio support for Zoom2"
- depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_ZOOM2
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TWL4030
- help
- Say Y if you want to add support for Soc audio on Zoom2 board.
-
-config SND_OMAP_SOC_IGEP0020
- tristate "SoC Audio support for IGEP v2"
- depends on TWL4030_CORE && SND_OMAP_SOC && MACH_IGEP0020
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TWL4030
- help
- Say Y if you want to add support for Soc audio on IGEP v2 board.
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index 1fd723fb559..a725905b2c6 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -1,7 +1,7 @@
# OMAP Platform Support
snd-soc-omap-objs := omap-pcm.o
snd-soc-omap-dmic-objs := omap-dmic.o
-snd-soc-omap-mcbsp-objs := omap-mcbsp.o
+snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o
snd-soc-omap-mcpdm-objs := omap-mcpdm.o
snd-soc-omap-hdmi-objs := omap-hdmi.o
@@ -16,29 +16,18 @@ 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-overo-objs := overo.o
-snd-soc-omap3evm-objs := omap3evm.o
snd-soc-am3517evm-objs := am3517evm.o
-snd-soc-sdp3430-objs := sdp3430.o
-snd-soc-sdp4430-objs := sdp4430.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
-snd-soc-omap3beagle-objs := omap3beagle.o
-snd-soc-zoom2-objs := zoom2.o
-snd-soc-igep0020-objs := igep0020.o
-snd-soc-omap4-hdmi-objs := omap4-hdmi-card.o
+snd-soc-omap-hdmi-card-objs := omap-hdmi-card.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_OVERO) += snd-soc-overo.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP2EVM) += snd-soc-omap2evm.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP3EVM) += snd-soc-omap3evm.o
obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o
-obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o
-obj-$(CONFIG_SND_OMAP_SOC_SDP4430) += snd-soc-sdp4430.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
-obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
-obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o
-obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) += snd-soc-omap4-hdmi.o
+obj-$(CONFIG_SND_OMAP_SOC_OMAP_HDMI) += snd-soc-omap-hdmi-card.o
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
index add4866d7e6..25a33e9d417 100644
--- a/sound/soc/omap/am3517evm.c
+++ b/sound/soc/omap/am3517evm.c
@@ -25,12 +25,9 @@
#include <sound/soc.h>
#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "omap-mcbsp.h"
-#include "omap-pcm.h"
#include "../codecs/tlv320aic23.h"
@@ -41,32 +38,15 @@ static int am3517evm_hw_params(struct snd_pcm_substream *substream,
{
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,
CODEC_CLOCK, SND_SOC_CLOCK_IN);
- if (ret < 0) {
+ if (ret < 0)
printk(KERN_ERR "can't set codec system clock\n");
- return ret;
- }
-
- ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_CLKR_SRC_CLKX, 0,
- SND_SOC_CLOCK_IN);
- if (ret < 0) {
- printk(KERN_ERR "can't set CPU system clock OMAP_MCBSP_CLKR_SRC_CLKX\n");
- return ret;
- }
- snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_FSR_SRC_FSX, 0,
- SND_SOC_CLOCK_IN);
- if (ret < 0) {
- printk(KERN_ERR "can't set CPU system clock OMAP_MCBSP_FSR_SRC_FSX\n");
- return ret;
- }
-
- return 0;
+ return ret;
}
static struct snd_soc_ops am3517evm_ops = {
@@ -95,9 +75,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
static struct snd_soc_dai_link am3517evm_dai = {
.name = "TLV320AIC23",
.stream_name = "AIC23",
- .cpu_dai_name ="omap-mcbsp-dai.0",
+ .cpu_dai_name = "omap-mcbsp.1",
.codec_dai_name = "tlv320aic23-hifi",
- .platform_name = "omap-pcm-audio",
+ .platform_name = "omap-mcbsp.1",
.codec_name = "tlv320aic23-codec.2-001a",
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index a67f4370bc9..0cc41f94de4 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -32,14 +32,12 @@
#include <asm/mach-types.h>
-#include <plat/board-ams-delta.h>
-#include <plat/mcbsp.h>
+#include <mach/board-ams-delta.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "omap-mcbsp.h"
-#include "omap-pcm.h"
#include "../codecs/cx20442.h"
-
/* Board specific DAPM widgets */
static const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = {
/* Handset */
@@ -91,73 +89,81 @@ static const unsigned short ams_delta_audio_mode_pins[] = {
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_codec *cx20442_codec;
+
static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ 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 (!codec->hw_write)
+ if (!cx20442_codec->hw_write)
return -EUNATCH;
- if (ucontrol->value.enumerated.item[0] >= control->max)
+ if (ucontrol->value.enumerated.item[0] >= control->items)
return -EINVAL;
- mutex_lock(&codec->mutex);
+ 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(dapm, "Mouthpiece");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Mouthpiece");
else
- snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
+ 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(dapm, "Earpiece");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece");
else
- snd_soc_dapm_disable_pin(dapm, "Earpiece");
+ 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(dapm, "Microphone");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone");
else
- snd_soc_dapm_disable_pin(dapm, "Microphone");
+ 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(dapm, "Speaker");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker");
else
- snd_soc_dapm_disable_pin(dapm, "Speaker");
+ 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(dapm, "AGCIN");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "AGCIN");
else
- snd_soc_dapm_disable_pin(dapm, "AGCIN");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN");
}
+
if (changed)
- snd_soc_dapm_sync(dapm);
+ snd_soc_dapm_sync_unlocked(dapm);
- mutex_unlock(&codec->mutex);
+ snd_soc_dapm_mutex_unlock(dapm);
return changed;
}
@@ -165,8 +171,8 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ 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") <<
@@ -195,13 +201,11 @@ static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol,
return 0;
}
-static const struct soc_enum ams_delta_audio_enum[] = {
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ams_delta_audio_mode),
- ams_delta_audio_mode),
-};
+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[0],
+ SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum,
ams_delta_get_audio_mode, ams_delta_set_audio_mode),
};
@@ -271,12 +275,6 @@ static void cx81801_timeout(unsigned long data)
ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC, 0);
}
-/*
- * Used for passing a codec structure pointer
- * from the board initialization code to the tty line discipline.
- */
-static struct snd_soc_codec *cx20442_codec;
-
/* Line discipline .open() */
static int cx81801_open(struct tty_struct *tty)
{
@@ -303,7 +301,7 @@ static int cx81801_open(struct tty_struct *tty)
static void cx81801_close(struct tty_struct *tty)
{
struct snd_soc_codec *codec = tty->disc_data;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dapm_context *dapm = &codec->card->dapm;
del_timer_sync(&cx81801_timer);
@@ -316,12 +314,17 @@ static void cx81801_close(struct tty_struct *tty)
v253_ops.close(tty);
/* Revert back to default audio input/output constellation */
- snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
- snd_soc_dapm_enable_pin(dapm, "Earpiece");
- snd_soc_dapm_enable_pin(dapm, "Microphone");
- snd_soc_dapm_disable_pin(dapm, "Speaker");
- snd_soc_dapm_disable_pin(dapm, "AGCIN");
- snd_soc_dapm_sync(dapm);
+ 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() */
@@ -426,29 +429,6 @@ static struct snd_soc_ops ams_delta_ops = {
};
-/* Board specific codec bias level control */
-static int ams_delta_set_bias_level(struct snd_soc_card *card,
- struct snd_soc_dapm_context *dapm,
- enum snd_soc_bias_level level)
-{
- switch (level) {
- case SND_SOC_BIAS_ON:
- case SND_SOC_BIAS_PREPARE:
- case SND_SOC_BIAS_STANDBY:
- if (card->dapm.bias_level == SND_SOC_BIAS_OFF)
- ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET,
- AMS_DELTA_LATCH2_MODEM_NRESET);
- break;
- case SND_SOC_BIAS_OFF:
- if (card->dapm.bias_level != SND_SOC_BIAS_OFF)
- ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET,
- 0);
- }
- card->dapm.bias_level = level;
-
- return 0;
-}
-
/* Digital mute implemented using modem/CPU multiplexer.
* Shares hardware with codec config pulse generation */
static bool ams_delta_muted = 1;
@@ -494,15 +474,14 @@ static void ams_delta_shutdown(struct snd_pcm_substream *substream)
static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
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 = codec;
+ cx20442_codec = rtd->codec;
/* Set up digital mute if not provided by the codec */
if (!codec_dai->driver->ops) {
@@ -512,9 +491,6 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
ams_delta_ops.shutdown = ams_delta_shutdown;
}
- /* Set codec bias level */
- ams_delta_set_bias_level(card, dapm, SND_SOC_BIAS_STANDBY);
-
/* Add hook switch - can be used to control the codec from userspace
* even if line discipline fails */
ret = snd_soc_jack_new(rtd->codec, "hook_switch",
@@ -542,40 +518,20 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
- /* Add board specific DAPM widgets and routes */
- ret = snd_soc_dapm_new_controls(dapm, ams_delta_dapm_widgets,
- ARRAY_SIZE(ams_delta_dapm_widgets));
- if (ret) {
- dev_warn(card->dev,
- "Failed to register DAPM controls, "
- "will continue without any.\n");
- return 0;
- }
-
- ret = snd_soc_dapm_add_routes(dapm, ams_delta_audio_map,
- ARRAY_SIZE(ams_delta_audio_map));
- if (ret) {
- dev_warn(card->dev,
- "Failed to set up DAPM routes, "
- "will continue with codec default map.\n");
- return 0;
- }
-
/* Set up initial pin constellation */
snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
- snd_soc_dapm_enable_pin(dapm, "Earpiece");
- snd_soc_dapm_enable_pin(dapm, "Microphone");
snd_soc_dapm_disable_pin(dapm, "Speaker");
snd_soc_dapm_disable_pin(dapm, "AGCIN");
snd_soc_dapm_disable_pin(dapm, "AGCOUT");
- /* Add virtual switch */
- ret = snd_soc_add_controls(codec, ams_delta_audio_controls,
- ARRAY_SIZE(ams_delta_audio_controls));
- if (ret)
- dev_warn(card->dev,
- "Failed to register audio mode control, "
- "will continue without it.\n");
+ return 0;
+}
+
+static int ams_delta_card_remove(struct snd_soc_card *card)
+{
+ snd_soc_jack_free_gpios(&ams_delta_hook_switch,
+ ARRAY_SIZE(ams_delta_hook_switch_gpios),
+ ams_delta_hook_switch_gpios);
return 0;
}
@@ -584,10 +540,10 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
static struct snd_soc_dai_link ams_delta_dai_link = {
.name = "CX20442",
.stream_name = "CX20442",
- .cpu_dai_name ="omap-mcbsp-dai.0",
+ .cpu_dai_name = "omap-mcbsp.1",
.codec_dai_name = "cx20442-voice",
.init = ams_delta_cx20442_init,
- .platform_name = "omap-pcm-audio",
+ .platform_name = "omap-mcbsp.1",
.codec_name = "cx20442-codec",
.ops = &ams_delta_ops,
};
@@ -596,67 +552,62 @@ static struct snd_soc_dai_link ams_delta_dai_link = {
static struct snd_soc_card ams_delta_audio_card = {
.name = "AMS_DELTA",
.owner = THIS_MODULE,
+ .remove = ams_delta_card_remove,
.dai_link = &ams_delta_dai_link,
.num_links = 1,
- .set_bias_level = ams_delta_set_bias_level,
+
+ .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 struct platform_device *ams_delta_audio_platform_device;
-static struct platform_device *cx20442_platform_device;
-
-static int __init ams_delta_module_init(void)
+static int ams_delta_probe(struct platform_device *pdev)
{
+ struct snd_soc_card *card = &ams_delta_audio_card;
int ret;
- if (!(machine_is_ams_delta()))
- return -ENODEV;
-
- ams_delta_audio_platform_device =
- platform_device_alloc("soc-audio", -1);
- if (!ams_delta_audio_platform_device)
- return -ENOMEM;
-
- platform_set_drvdata(ams_delta_audio_platform_device,
- &ams_delta_audio_card);
+ card->dev = &pdev->dev;
- ret = platform_device_add(ams_delta_audio_platform_device);
- if (ret)
- goto err;
-
- /*
- * Codec platform device could be registered from elsewhere (board?),
- * but I do it here as it makes sense only if used with the card.
- */
- cx20442_platform_device =
- platform_device_register_simple("cx20442-codec", -1, NULL, 0);
+ 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;
-err:
- platform_device_put(ams_delta_audio_platform_device);
- return ret;
}
-module_init(ams_delta_module_init);
-static void __exit ams_delta_module_exit(void)
+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(&ams_delta_audio_platform_device->dev,
+ dev_warn(&pdev->dev,
"failed to unregister V253 line discipline\n");
- snd_soc_jack_free_gpios(&ams_delta_hook_switch,
- ARRAY_SIZE(ams_delta_hook_switch_gpios),
- ams_delta_hook_switch_gpios);
+ snd_soc_unregister_card(card);
+ card->dev = NULL;
+ return 0;
+}
- /* Keep modem power on */
- ams_delta_set_bias_level(&ams_delta_audio_card,
- &ams_delta_audio_card.rtd[0].codec->dapm,
- SND_SOC_BIAS_STANDBY);
+#define DRV_NAME "ams-delta-audio"
- platform_device_unregister(cx20442_platform_device);
- platform_device_unregister(ams_delta_audio_platform_device);
-}
-module_exit(ams_delta_module_exit);
+static struct platform_driver ams_delta_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .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/igep0020.c b/sound/soc/omap/igep0020.c
deleted file mode 100644
index ccae58a1339..00000000000
--- a/sound/soc/omap/igep0020.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * igep0020.c -- SoC audio for IGEP v2
- *
- * Based on sound/soc/omap/overo.c by Steve Sakoman
- *
- * 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/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <plat/mcbsp.h>
-
-#include "omap-mcbsp.h"
-#include "omap-pcm.h"
-
-static int igep2_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 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) {
- printk(KERN_ERR "can't set codec system clock\n");
- return ret;
- }
-
- return 0;
-}
-
-static struct snd_soc_ops igep2_ops = {
- .hw_params = igep2_hw_params,
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link igep2_dai = {
- .name = "TWL4030",
- .stream_name = "TWL4030",
- .cpu_dai_name = "omap-mcbsp-dai.1",
- .codec_dai_name = "twl4030-hifi",
- .platform_name = "omap-pcm-audio",
- .codec_name = "twl4030-codec",
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
- .ops = &igep2_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_card_igep2 = {
- .name = "igep2",
- .owner = THIS_MODULE,
- .dai_link = &igep2_dai,
- .num_links = 1,
-};
-
-static struct platform_device *igep2_snd_device;
-
-static int __init igep2_soc_init(void)
-{
- int ret;
-
- if (!machine_is_igep0020())
- return -ENODEV;
- printk(KERN_INFO "IGEP v2 SoC init\n");
-
- igep2_snd_device = platform_device_alloc("soc-audio", -1);
- if (!igep2_snd_device) {
- printk(KERN_ERR "Platform device allocation failed\n");
- return -ENOMEM;
- }
-
- platform_set_drvdata(igep2_snd_device, &snd_soc_card_igep2);
-
- ret = platform_device_add(igep2_snd_device);
- if (ret)
- goto err1;
-
- return 0;
-
-err1:
- printk(KERN_ERR "Unable to add platform device\n");
- platform_device_put(igep2_snd_device);
-
- return ret;
-}
-module_init(igep2_soc_init);
-
-static void __exit igep2_soc_exit(void)
-{
- platform_device_unregister(igep2_snd_device);
-}
-module_exit(igep2_soc_exit);
-
-MODULE_AUTHOR("Enric Balletbo i Serra <eballetbo@iseebcn.com>");
-MODULE_DESCRIPTION("ALSA SoC IGEP v2");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
new file mode 100644
index 00000000000..86c75384c3c
--- /dev/null
+++ b/sound/soc/omap/mcbsp.c
@@ -0,0 +1,1101 @@
+/*
+ * sound/soc/omap/mcbsp.c
+ *
+ * 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>
+ *
+ * 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.
+ *
+ * Multichannel mode not supported.
+ */
+
+#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 <linux/platform_data/asoc-ti-mcbsp.h>
+
+#include "mcbsp.h"
+
+static 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 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];
+ }
+}
+
+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_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)
+
+#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_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 irqreturn_t omap_mcbsp_irq_handler(int irq, void *dev_id)
+{
+ struct omap_mcbsp *mcbsp = dev_id;
+ 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 *dev_id)
+{
+ struct omap_mcbsp *mcbsp_tx = dev_id;
+ u16 irqst_spcr2;
+
+ irqst_spcr2 = MCBSP_READ(mcbsp_tx, SPCR2);
+ dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
+
+ if (irqst_spcr2 & XSYNC_ERR) {
+ dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n",
+ irqst_spcr2);
+ /* Writing zero to XSYNC_ERR clears the IRQ */
+ MCBSP_WRITE(mcbsp_tx, SPCR2, MCBSP_READ_CACHE(mcbsp_tx, SPCR2));
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
+{
+ struct omap_mcbsp *mcbsp_rx = dev_id;
+ u16 irqst_spcr1;
+
+ irqst_spcr1 = MCBSP_READ(mcbsp_rx, SPCR1);
+ dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
+
+ if (irqst_spcr1 & RSYNC_ERR) {
+ dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n",
+ irqst_spcr1);
+ /* Writing zero to RSYNC_ERR clears the IRQ */
+ MCBSP_WRITE(mcbsp_rx, SPCR1, MCBSP_READ_CACHE(mcbsp_rx, 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().
+ */
+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);
+}
+
+/**
+ * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
+ * @id - mcbsp id
+ * @stream - indicates the direction of data flow (rx or tx)
+ *
+ * Returns the address of mcbsp data transmit register or data receive register
+ * to be used by DMA for transferring/receiving data based on the value of
+ * @stream for the requested mcbsp given by @id
+ */
+static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp,
+ unsigned int stream)
+{
+ int data_reg;
+
+ if (mcbsp->pdata->reg_size == 2) {
+ if (stream)
+ data_reg = OMAP_MCBSP_REG_DRR1;
+ else
+ data_reg = OMAP_MCBSP_REG_DXR1;
+ } else {
+ if (stream)
+ data_reg = OMAP_MCBSP_REG_DRR;
+ else
+ data_reg = OMAP_MCBSP_REG_DXR;
+ }
+
+ return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step;
+}
+
+static void omap_st_on(struct omap_mcbsp *mcbsp)
+{
+ unsigned int w;
+
+ if (mcbsp->pdata->enable_st_clock)
+ mcbsp->pdata->enable_st_clock(mcbsp->id, 1);
+
+ /* 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_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));
+
+ if (mcbsp->pdata->enable_st_clock)
+ mcbsp->pdata->enable_st_clock(mcbsp->id, 0);
+}
+
+static void omap_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_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));
+}
+
+int omap_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_st_chgain(mcbsp);
+ spin_unlock_irq(&mcbsp->lock);
+
+ return ret;
+}
+
+int omap_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_st_start(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ if (st_data->enabled && !st_data->running) {
+ omap_st_fir_write(mcbsp, st_data->taps);
+ omap_st_chgain(mcbsp);
+
+ if (!mcbsp->free) {
+ omap_st_on(mcbsp);
+ st_data->running = 1;
+ }
+ }
+
+ return 0;
+}
+
+int omap_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_st_start(mcbsp);
+ spin_unlock_irq(&mcbsp->lock);
+
+ return 0;
+}
+
+static int omap_st_stop(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ if (st_data->running) {
+ if (!mcbsp->free) {
+ omap_st_off(mcbsp);
+ st_data->running = 0;
+ }
+ }
+
+ return 0;
+}
+
+int omap_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_st_stop(mcbsp);
+ st_data->enabled = 0;
+ spin_unlock_irq(&mcbsp->lock);
+
+ return ret;
+}
+
+int omap_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;
+}
+
+/*
+ * 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.
+ */
+void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
+{
+ if (mcbsp->pdata->buffer_size == 0)
+ return;
+
+ 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.
+ */
+void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
+{
+ if (mcbsp->pdata->buffer_size == 0)
+ return;
+
+ 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
+ */
+u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp)
+{
+ u16 buffstat;
+
+ if (mcbsp->pdata->buffer_size == 0)
+ return 0;
+
+ /* 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)
+ */
+u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp)
+{
+ u16 buffstat, threshold;
+
+ if (mcbsp->pdata->buffer_size == 0)
+ return 0;
+
+ /* 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;
+}
+
+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 && 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 && 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;
+}
+
+void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
+{
+ void *reg_cache;
+
+ if (mcbsp->pdata && 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);
+
+ if (reg_cache)
+ 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.
+ */
+void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx)
+{
+ int enable_srg = 0;
+ u16 w;
+
+ if (mcbsp->st_data)
+ omap_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);
+}
+
+void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx)
+{
+ 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_st_stop(mcbsp);
+}
+
+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;
+
+}
+
+#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 *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);
+ const char * const *s;
+ int i = 0;
+
+ for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++)
+ if (sysfs_streq(buf, *s))
+ break;
+
+ if (i == ARRAY_SIZE(dma_op_modes))
+ return -EINVAL;
+
+ 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(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store);
+
+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,
+};
+
+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(st_taps, 0644, st_taps_show, st_taps_store);
+
+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,
+};
+
+static int omap_st_add(struct omap_mcbsp *mcbsp, struct resource *res)
+{
+ struct omap_mcbsp_st_data *st_data;
+ int err;
+
+ st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL);
+ if (!st_data)
+ return -ENOMEM;
+
+ st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start,
+ resource_size(res));
+ if (!st_data->io_base_st)
+ return -ENOMEM;
+
+ err = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
+ if (err)
+ return err;
+
+ mcbsp->st_data = st_data;
+ return 0;
+}
+
+/*
+ * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
+ * 730 has only 2 McBSP, and both of them are MPU peripherals.
+ */
+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);
+ if (!res) {
+ dev_err(mcbsp->dev, "invalid memory resource\n");
+ return -ENOMEM;
+ }
+ }
+ if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
+ dev_name(&pdev->dev))) {
+ dev_err(mcbsp->dev, "memory region already claimed\n");
+ return -ENODEV;
+ }
+
+ mcbsp->phys_base = res->start;
+ mcbsp->reg_cache_size = resource_size(res);
+ mcbsp->io_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!mcbsp->io_base)
+ return -ENOMEM;
+
+ 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, 0);
+ mcbsp->dma_data[0].maxburst = 4;
+
+ mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
+ mcbsp->dma_data[1].maxburst = 4;
+
+ 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;
+ }
+ } else {
+ mcbsp->max_tx_thres = -EINVAL;
+ mcbsp->max_rx_thres = -EINVAL;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
+ if (res) {
+ ret = omap_st_add(mcbsp, res);
+ if (ret) {
+ dev_err(mcbsp->dev,
+ "Unable to create sidetone controls\n");
+ 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;
+}
+
+void omap_mcbsp_sysfs_remove(struct omap_mcbsp *mcbsp)
+{
+ if (mcbsp->pdata->buffer_size)
+ sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
+
+ if (mcbsp->st_data)
+ sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
+}
diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/mcbsp.h
new file mode 100644
index 00000000000..96d1b086bcf
--- /dev/null
+++ b/sound/soc/omap/mcbsp.h
@@ -0,0 +1,354 @@
+/*
+ * sound/soc/omap/mcbsp.h
+ *
+ * OMAP Multi-Channel Buffered Serial Port
+ *
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __ASOC_MCBSP_H
+#define __ASOC_MCBSP_H
+
+#ifdef CONFIG_ARCH_OMAP1
+#define mcbsp_omap1() 1
+#else
+#define mcbsp_omap1() 0
+#endif
+
+#include <sound/dmaengine_pcm.h>
+
+/* 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,
+};
+
+/* 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 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 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)
+
+/********************** 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 {
+ void __iomem *io_base_st;
+ bool running;
+ bool enabled;
+ s16 taps[128]; /* Sidetone filter coefficients */
+ int nr_taps; /* Number of filter coefficients in use */
+ s16 ch0gain;
+ s16 ch1gain;
+};
+
+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;
+ int clk_div;
+ int wlen;
+};
+
+void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
+ const struct omap_mcbsp_reg_cfg *config);
+void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold);
+void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold);
+u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp);
+u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp);
+int omap_mcbsp_get_dma_op_mode(struct omap_mcbsp *mcbsp);
+int omap_mcbsp_request(struct omap_mcbsp *mcbsp);
+void omap_mcbsp_free(struct omap_mcbsp *mcbsp);
+void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx);
+void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx);
+
+/* McBSP functional clock source changing function */
+int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id);
+
+/* Sidetone specific API */
+int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain);
+int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain);
+int omap_st_enable(struct omap_mcbsp *mcbsp);
+int omap_st_disable(struct omap_mcbsp *mcbsp);
+int omap_st_is_enabled(struct omap_mcbsp *mcbsp);
+
+int omap_mcbsp_init(struct platform_device *pdev);
+void omap_mcbsp_sysfs_remove(struct omap_mcbsp *mcbsp);
+
+#endif /* __ASOC_MCBSP_H */
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 597be412f1e..5d7f9cebe04 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -29,13 +29,11 @@
#include <sound/soc.h>
#include <asm/mach-types.h>
-#include <mach/hardware.h>
#include <linux/gpio.h>
#include <linux/module.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "omap-mcbsp.h"
-#include "omap-pcm.h"
#define N810_HEADSET_AMP_GPIO 10
#define N810_SPEAKER_AMP_GPIO 101
@@ -55,9 +53,8 @@ static int n810_spk_func;
static int n810_jack_func;
static int n810_dmic_func;
-static void n810_ext_control(struct snd_soc_codec *codec)
+static void n810_ext_control(struct snd_soc_dapm_context *dapm)
{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
int hp = 0, line1l = 0;
switch (n810_jack_func) {
@@ -71,26 +68,30 @@ static void n810_ext_control(struct snd_soc_codec *codec)
break;
}
+ snd_soc_dapm_mutex_lock(dapm);
+
if (n810_spk_func)
- snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
else
- snd_soc_dapm_disable_pin(dapm, "Ext Spk");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
if (hp)
- snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
else
- snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
if (line1l)
- snd_soc_dapm_enable_pin(dapm, "LINE1L");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "LINE1L");
else
- snd_soc_dapm_disable_pin(dapm, "LINE1L");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "LINE1L");
if (n810_dmic_func)
- snd_soc_dapm_enable_pin(dapm, "DMic");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "DMic");
else
- snd_soc_dapm_disable_pin(dapm, "DMic");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "DMic");
+
+ snd_soc_dapm_sync_unlocked(dapm);
- snd_soc_dapm_sync(dapm);
+ snd_soc_dapm_mutex_unlock(dapm);
}
static int n810_startup(struct snd_pcm_substream *substream)
@@ -102,13 +103,13 @@ static int n810_startup(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
- n810_ext_control(codec);
- return clk_enable(sys_clkout2);
+ n810_ext_control(&codec->dapm);
+ return clk_prepare_enable(sys_clkout2);
}
static void n810_shutdown(struct snd_pcm_substream *substream)
{
- clk_disable(sys_clkout2);
+ clk_disable_unprepare(sys_clkout2);
}
static int n810_hw_params(struct snd_pcm_substream *substream,
@@ -142,13 +143,13 @@ static int n810_get_spk(struct snd_kcontrol *kcontrol,
static int n810_set_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
if (n810_spk_func == ucontrol->value.integer.value[0])
return 0;
n810_spk_func = ucontrol->value.integer.value[0];
- n810_ext_control(codec);
+ n810_ext_control(&card->dapm);
return 1;
}
@@ -164,13 +165,13 @@ static int n810_get_jack(struct snd_kcontrol *kcontrol,
static int n810_set_jack(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
if (n810_jack_func == ucontrol->value.integer.value[0])
return 0;
n810_jack_func = ucontrol->value.integer.value[0];
- n810_ext_control(codec);
+ n810_ext_control(&card->dapm);
return 1;
}
@@ -186,13 +187,13 @@ static int n810_get_input(struct snd_kcontrol *kcontrol,
static int n810_set_input(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
if (n810_dmic_func == ucontrol->value.integer.value[0])
return 0;
n810_dmic_func = ucontrol->value.integer.value[0];
- n810_ext_control(codec);
+ n810_ext_control(&card->dapm);
return 1;
}
@@ -232,8 +233,8 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Ext Spk", NULL, "LLOUT"},
{"Ext Spk", NULL, "RLOUT"},
- {"DMic Rate 64", NULL, "Mic Bias 2V"},
- {"Mic Bias 2V", NULL, "DMic"},
+ {"DMic Rate 64", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "DMic"},
};
static const char *spk_function[] = {"Off", "On"};
@@ -276,8 +277,8 @@ static int n810_aic33_init(struct snd_soc_pcm_runtime *rtd)
static struct snd_soc_dai_link n810_dai = {
.name = "TLV320AIC33",
.stream_name = "AIC33",
- .cpu_dai_name = "omap-mcbsp-dai.1",
- .platform_name = "omap-pcm-audio",
+ .cpu_dai_name = "omap-mcbsp.2",
+ .platform_name = "omap-mcbsp.2",
.codec_name = "tlv320aic3x-codec.2-0018",
.codec_dai_name = "tlv320aic3x-hifi",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
@@ -308,7 +309,9 @@ static int __init n810_soc_init(void)
int err;
struct device *dev;
- if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax()))
+ 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);
@@ -347,8 +350,11 @@ static int __init n810_soc_init(void)
clk_set_parent(sys_clkout2_src, func96m_clk);
clk_set_rate(sys_clkout2, 12000000);
- BUG_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) ||
- (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0));
+ 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);
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
new file mode 100644
index 00000000000..cec836ed0c0
--- /dev/null
+++ b/sound/soc/omap/omap-abe-twl6040.c
@@ -0,0 +1,370 @@
+/*
+ * 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 {
+ int jack_detection; /* board can detect jack events */
+ int mclk_freq; /* MCLK frequency speed for twl6040 */
+
+ 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(rtd->codec);
+ 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 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_codec *codec = rtd->codec;
+ 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(codec, 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_jack_new(codec, "Headset Jack",
+ SND_JACK_HEADSET, &hs_jack);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+ hs_jack_pins);
+ twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
+ }
+
+ return ret;
+}
+
+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));
+}
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link abe_twl6040_dai_links[] = {
+ {
+ .name = "TWL6040",
+ .stream_name = "TWL6040",
+ .codec_dai_name = "twl6040-legacy",
+ .codec_name = "twl6040-codec",
+ .init = omap_abe_twl6040_init,
+ .ops = &omap_abe_ops,
+ },
+ {
+ .name = "DMIC",
+ .stream_name = "DMIC Capture",
+ .codec_dai_name = "dmic-hifi",
+ .codec_name = "dmic-codec",
+ .init = omap_abe_dmic_init,
+ .ops = &omap_abe_dmic_ops,
+ },
+};
+
+/* Audio machine driver */
+static struct snd_soc_card omap_abe_card = {
+ .owner = THIS_MODULE,
+
+ .dapm_widgets = twl6040_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static int omap_abe_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct snd_soc_card *card = &omap_abe_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;
+ }
+
+ card->dev = &pdev->dev;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+
+ priv->dmic_codec_dev = ERR_PTR(-EINVAL);
+
+ 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;
+ }
+ abe_twl6040_dai_links[0].cpu_of_node = dai_node;
+ abe_twl6040_dai_links[0].platform_of_node = dai_node;
+
+ dai_node = of_parse_phandle(node, "ti,dmic", 0);
+ if (dai_node) {
+ num_links = 2;
+ abe_twl6040_dai_links[1].cpu_of_node = dai_node;
+ abe_twl6040_dai_links[1].platform_of_node = dai_node;
+
+ priv->dmic_codec_dev = platform_device_register_simple(
+ "dmic-codec", -1, NULL, 0);
+ if (IS_ERR(priv->dmic_codec_dev)) {
+ dev_err(&pdev->dev, "Can't instantiate dmic-codec\n");
+ return PTR_ERR(priv->dmic_codec_dev);
+ }
+ } 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");
+ ret = -EINVAL;
+ goto err_unregister;
+ }
+
+ card->fully_routed = 1;
+
+ if (!priv->mclk_freq) {
+ dev_err(&pdev->dev, "MCLK frequency missing\n");
+ ret = -ENODEV;
+ goto err_unregister;
+ }
+
+ card->dai_link = abe_twl6040_dai_links;
+ card->num_links = num_links;
+
+ snd_soc_card_set_drvdata(card, priv);
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+ ret);
+ goto err_unregister;
+ }
+
+ return 0;
+
+err_unregister:
+ if (!IS_ERR(priv->dmic_codec_dev))
+ platform_device_unregister(priv->dmic_codec_dev);
+
+ return ret;
+}
+
+static int omap_abe_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
+
+ snd_soc_unregister_card(card);
+
+ if (!IS_ERR(priv->dmic_codec_dev))
+ platform_device_unregister(priv->dmic_codec_dev);
+
+ return 0;
+}
+
+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",
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = omap_abe_of_match,
+ },
+ .probe = omap_abe_probe,
+ .remove = omap_abe_remove,
+};
+
+module_platform_driver(omap_abe_driver);
+
+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
index 0855c1cfa7f..6925d714121 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/omap/omap-dmic.c
@@ -32,15 +32,16 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
-#include <plat/dma.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 <sound/omap-pcm.h>
-#include "omap-pcm.h"
#include "omap-dmic.h"
struct omap_dmic {
@@ -55,25 +56,18 @@ struct omap_dmic {
u32 ch_enabled;
bool active;
struct mutex mutex;
-};
-/*
- * Stream DMA parameters
- */
-static struct omap_pcm_dma_data omap_dmic_dai_dma_params = {
- .name = "DMIC capture",
- .data_type = OMAP_DMA_DATA_TYPE_S32,
- .sync_mode = OMAP_DMA_SYNC_PACKET,
+ struct snd_dmaengine_dai_dma_data dma_data;
};
static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val)
{
- __raw_writel(val, dmic->io_base + reg);
+ writel_relaxed(val, dmic->io_base + reg);
}
static inline int omap_dmic_read(struct omap_dmic *dmic, u16 reg)
{
- return __raw_readl(dmic->io_base + reg);
+ return readl_relaxed(dmic->io_base + reg);
}
static inline void omap_dmic_start(struct omap_dmic *dmic)
@@ -113,12 +107,10 @@ static int omap_dmic_dai_startup(struct snd_pcm_substream *substream,
mutex_lock(&dmic->mutex);
- if (!dai->active) {
- snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24);
+ if (!dai->active)
dmic->active = 1;
- } else {
+ else
ret = -EBUSY;
- }
mutex_unlock(&dmic->mutex);
@@ -206,6 +198,7 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
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));
@@ -231,8 +224,8 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
}
/* packet size is threshold * channels */
- omap_dmic_dai_dma_params.packet_size = dmic->threshold * channels;
- snd_soc_dai_set_dma_data(dai, substream, &omap_dmic_dai_dma_params);
+ dma_data = snd_soc_dai_get_dma_data(dai, substream);
+ dma_data->maxburst = dmic->threshold * channels;
return 0;
}
@@ -424,6 +417,9 @@ static int omap_dmic_probe(struct snd_soc_dai *dai)
/* Configure DMIC threshold value */
dmic->threshold = OMAP_DMIC_THRES_MAX - 3;
+
+ snd_soc_dai_init_dma_data(dai, NULL, &dmic->dma_data);
+
return 0;
}
@@ -445,11 +441,16 @@ static struct snd_soc_dai_driver omap_dmic_dai = {
.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 __devinit int asoc_dmic_probe(struct platform_device *pdev)
+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;
@@ -465,9 +466,9 @@ static __devinit int asoc_dmic_probe(struct platform_device *pdev)
mutex_init(&dmic->mutex);
- dmic->fclk = clk_get(dmic->dev, "dmic_fck");
+ dmic->fclk = clk_get(dmic->dev, "fck");
if (IS_ERR(dmic->fclk)) {
- dev_err(dmic->dev, "cant get dmic_fck\n");
+ dev_err(dmic->dev, "cant get fck\n");
return -ENODEV;
}
@@ -477,38 +478,24 @@ static __devinit int asoc_dmic_probe(struct platform_device *pdev)
ret = -ENODEV;
goto err_put_clk;
}
- omap_dmic_dai_dma_params.port_addr = res->start + OMAP_DMIC_DATA_REG;
+ dmic->dma_data.addr = res->start + OMAP_DMIC_DATA_REG;
- res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!res) {
- dev_err(dmic->dev, "invalid dma resource\n");
- ret = -ENODEV;
- goto err_put_clk;
- }
- omap_dmic_dai_dma_params.dma_req = res->start;
+ dmic->dma_data.filter_data = "up_link";
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
- if (!res) {
- dev_err(dmic->dev, "invalid memory resource\n");
- ret = -ENODEV;
+ dmic->io_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dmic->io_base)) {
+ ret = PTR_ERR(dmic->io_base);
goto err_put_clk;
}
- if (!devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), pdev->name)) {
- dev_err(dmic->dev, "memory region already claimed\n");
- ret = -ENODEV;
- goto err_put_clk;
- }
- dmic->io_base = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!dmic->io_base) {
- ret = -ENOMEM;
+ ret = snd_soc_register_component(&pdev->dev, &omap_dmic_component,
+ &omap_dmic_dai, 1);
+ if (ret)
goto err_put_clk;
- }
- ret = snd_soc_register_dai(&pdev->dev, &omap_dmic_dai);
+ ret = omap_pcm_platform_register(&pdev->dev);
if (ret)
goto err_put_clk;
@@ -519,23 +506,30 @@ err_put_clk:
return ret;
}
-static int __devexit asoc_dmic_remove(struct platform_device *pdev)
+static int asoc_dmic_remove(struct platform_device *pdev)
{
struct omap_dmic *dmic = platform_get_drvdata(pdev);
- snd_soc_unregister_dai(&pdev->dev);
+ snd_soc_unregister_component(&pdev->dev);
clk_put(dmic->fclk);
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",
.owner = THIS_MODULE,
+ .of_match_table = omap_dmic_of_match,
},
.probe = asoc_dmic_probe,
- .remove = __devexit_p(asoc_dmic_remove),
+ .remove = asoc_dmic_remove,
};
module_platform_driver(asoc_dmic_driver);
diff --git a/sound/soc/omap/omap-hdmi-card.c b/sound/soc/omap/omap-hdmi-card.c
new file mode 100644
index 00000000000..f649fe84b62
--- /dev/null
+++ b/sound/soc/omap/omap-hdmi-card.c
@@ -0,0 +1,87 @@
+/*
+ * omap-hdmi-card.c
+ *
+ * OMAP ALSA SoC machine driver for TI OMAP HDMI
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Ricardo Neri <ricardo.neri@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/module.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <asm/mach-types.h>
+#include <video/omapdss.h>
+
+#define DRV_NAME "omap-hdmi-audio"
+
+static struct snd_soc_dai_link omap_hdmi_dai = {
+ .name = "HDMI",
+ .stream_name = "HDMI",
+ .cpu_dai_name = "omap-hdmi-audio-dai",
+ .platform_name = "omap-hdmi-audio-dai",
+ .codec_name = "hdmi-audio-codec",
+ .codec_dai_name = "hdmi-hifi",
+};
+
+static struct snd_soc_card snd_soc_omap_hdmi = {
+ .name = "OMAPHDMI",
+ .owner = THIS_MODULE,
+ .dai_link = &omap_hdmi_dai,
+ .num_links = 1,
+};
+
+static int omap_hdmi_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &snd_soc_omap_hdmi;
+ 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 omap_hdmi_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_card(card);
+ card->dev = NULL;
+ return 0;
+}
+
+static struct platform_driver omap_hdmi_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = omap_hdmi_probe,
+ .remove = omap_hdmi_remove,
+};
+
+module_platform_driver(omap_hdmi_driver);
+
+MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
+MODULE_DESCRIPTION("OMAP HDMI machine ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c
index 38e0defa707..eb9c39299f8 100644
--- a/sound/soc/omap/omap-hdmi.c
+++ b/sound/soc/omap/omap-hdmi.c
@@ -30,21 +30,29 @@
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
+#include <sound/asound.h>
+#include <sound/asoundef.h>
+#include <sound/dmaengine_pcm.h>
+#include <video/omapdss.h>
+#include <sound/omap-pcm.h>
-#include <plat/dma.h>
-#include "omap-pcm.h"
#include "omap-hdmi.h"
-#define DRV_NAME "hdmi-audio-dai"
+#define DRV_NAME "omap-hdmi-audio-dai"
-static struct omap_pcm_dma_data omap_hdmi_dai_dma_params = {
- .name = "HDMI playback",
- .sync_mode = OMAP_DMA_SYNC_PACKET,
+struct hdmi_priv {
+ struct snd_dmaengine_dai_dma_data dma_data;
+ unsigned int dma_req;
+ struct omap_dss_audio dss_audio;
+ struct snd_aes_iec958 iec;
+ struct snd_cea_861_aud_if cea;
+ struct omap_dss_device *dssdev;
};
static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
int err;
/*
* Make sure that the period bytes are multiple of the DMA packet size.
@@ -52,81 +60,289 @@ static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
*/
err = snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
- if (err < 0)
+ if (err < 0) {
+ dev_err(dai->dev, "could not apply constraint\n");
return err;
+ }
+
+ if (!priv->dssdev->driver->audio_supported(priv->dssdev)) {
+ dev_err(dai->dev, "audio not supported\n");
+ return -ENODEV;
+ }
+
+ snd_soc_dai_set_dma_data(dai, substream, &priv->dma_data);
return 0;
}
+static int omap_hdmi_dai_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
+
+ return priv->dssdev->driver->audio_enable(priv->dssdev);
+}
+
static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
+ struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
+ struct snd_aes_iec958 *iec = &priv->iec;
+ struct snd_cea_861_aud_if *cea = &priv->cea;
int err = 0;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
- omap_hdmi_dai_dma_params.packet_size = 16;
+ priv->dma_data.maxburst = 16;
break;
case SNDRV_PCM_FORMAT_S24_LE:
- omap_hdmi_dai_dma_params.packet_size = 32;
+ priv->dma_data.maxburst = 32;
break;
default:
- err = -EINVAL;
+ dev_err(dai->dev, "format not supported!\n");
+ return -EINVAL;
}
- omap_hdmi_dai_dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
+ /*
+ * fill the IEC-60958 channel status word
+ */
+ /* initialize the word bytes */
+ memset(iec->status, 0, sizeof(iec->status));
- snd_soc_dai_set_dma_data(dai, substream,
- &omap_hdmi_dai_dma_params);
+ /* 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[0] |= IEC958_AES1_PRO_MODE_NOTID;
+
+ 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 */
+
+ /*
+ * The OMAP HDMI IP requires to use the 8-channel channel code when
+ * transmitting more than two channels.
+ */
+ if (params_channels(params) == 2)
+ cea->db4_ca = 0x0;
+ else
+ cea->db4_ca = 0x13;
+
+ 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);
+
+ priv->dss_audio.iec = iec;
+ priv->dss_audio.cea = cea;
+
+ err = priv->dssdev->driver->audio_config(priv->dssdev,
+ &priv->dss_audio);
+
+ return err;
+}
+
+static int omap_hdmi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
+ int err = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ err = priv->dssdev->driver->audio_start(priv->dssdev);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ priv->dssdev->driver->audio_stop(priv->dssdev);
+ break;
+ default:
+ err = -EINVAL;
+ }
return err;
}
+static void omap_hdmi_dai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
+
+ priv->dssdev->driver->audio_disable(priv->dssdev);
+}
+
static const struct snd_soc_dai_ops omap_hdmi_dai_ops = {
.startup = omap_hdmi_dai_startup,
.hw_params = omap_hdmi_dai_hw_params,
+ .prepare = omap_hdmi_dai_prepare,
+ .trigger = omap_hdmi_dai_trigger,
+ .shutdown = omap_hdmi_dai_shutdown,
};
static struct snd_soc_dai_driver omap_hdmi_dai = {
.playback = {
.channels_min = 2,
- .channels_max = 2,
+ .channels_max = 8,
.rates = OMAP_HDMI_RATES,
.formats = OMAP_HDMI_FORMATS,
},
.ops = &omap_hdmi_dai_ops,
};
-static __devinit int omap_hdmi_probe(struct platform_device *pdev)
+static const struct snd_soc_component_driver omap_hdmi_component = {
+ .name = DRV_NAME,
+};
+
+static int omap_hdmi_probe(struct platform_device *pdev)
{
int ret;
struct resource *hdmi_rsrc;
+ struct hdmi_priv *hdmi_data;
+ bool hdmi_dev_found = false;
+
+ hdmi_data = devm_kzalloc(&pdev->dev, sizeof(*hdmi_data), GFP_KERNEL);
+ if (hdmi_data == NULL) {
+ dev_err(&pdev->dev, "Cannot allocate memory for HDMI data\n");
+ return -ENOMEM;
+ }
hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!hdmi_rsrc) {
dev_err(&pdev->dev, "Cannot obtain IORESOURCE_MEM HDMI\n");
- return -EINVAL;
+ return -ENODEV;
}
- omap_hdmi_dai_dma_params.port_addr = hdmi_rsrc->start
- + OMAP_HDMI_AUDIO_DMA_PORT;
+ hdmi_data->dma_data.addr = hdmi_rsrc->start + OMAP_HDMI_AUDIO_DMA_PORT;
hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!hdmi_rsrc) {
dev_err(&pdev->dev, "Cannot obtain IORESOURCE_DMA HDMI\n");
- return -EINVAL;
+ return -ENODEV;
+ }
+
+ hdmi_data->dma_req = hdmi_rsrc->start;
+ hdmi_data->dma_data.filter_data = &hdmi_data->dma_req;
+ hdmi_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+ /*
+ * TODO: We assume that there is only one DSS HDMI device. Future
+ * OMAP implementations may support more than one HDMI devices and
+ * we should provided separate audio support for all of them.
+ */
+ /* Find an HDMI device. */
+ for_each_dss_dev(hdmi_data->dssdev) {
+ omap_dss_get_device(hdmi_data->dssdev);
+
+ if (!hdmi_data->dssdev->driver) {
+ omap_dss_put_device(hdmi_data->dssdev);
+ continue;
+ }
+
+ if (hdmi_data->dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
+ hdmi_dev_found = true;
+ break;
+ }
+ }
+
+ if (!hdmi_dev_found) {
+ dev_err(&pdev->dev, "no driver for HDMI display found\n");
+ return -ENODEV;
}
- omap_hdmi_dai_dma_params.dma_req = hdmi_rsrc->start;
+ dev_set_drvdata(&pdev->dev, hdmi_data);
+ ret = snd_soc_register_component(&pdev->dev, &omap_hdmi_component,
+ &omap_hdmi_dai, 1);
- ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai);
- return ret;
+ if (ret)
+ return ret;
+
+ return omap_pcm_platform_register(&pdev->dev);
}
-static int __devexit omap_hdmi_remove(struct platform_device *pdev)
+static int omap_hdmi_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&pdev->dev);
+ struct hdmi_priv *hdmi_data = dev_get_drvdata(&pdev->dev);
+
+ snd_soc_unregister_component(&pdev->dev);
+
+ if (hdmi_data == NULL) {
+ dev_err(&pdev->dev, "cannot obtain HDMi data\n");
+ return -ENODEV;
+ }
+
+ omap_dss_put_device(hdmi_data->dssdev);
return 0;
}
@@ -136,7 +352,7 @@ static struct platform_driver hdmi_dai_driver = {
.owner = THIS_MODULE,
},
.probe = omap_hdmi_probe,
- .remove = __devexit_p(omap_hdmi_remove),
+ .remove = omap_hdmi_remove,
};
module_platform_driver(hdmi_dai_driver);
diff --git a/sound/soc/omap/omap-hdmi.h b/sound/soc/omap/omap-hdmi.h
index 34c298d5057..6ad2bf4f269 100644
--- a/sound/soc/omap/omap-hdmi.h
+++ b/sound/soc/omap/omap-hdmi.h
@@ -28,7 +28,9 @@
#define OMAP_HDMI_AUDIO_DMA_PORT 0x8c
#define OMAP_HDMI_RATES (SNDRV_PCM_RATE_32000 | \
- SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
#define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE)
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 017371913ec..efe2cd699b7 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -25,16 +25,20 @@
#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 <sound/omap-pcm.h>
-#include <plat/dma.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
+#include "mcbsp.h"
#include "omap-mcbsp.h"
-#include "omap-pcm.h"
#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000)
@@ -46,60 +50,43 @@
.private_value = (unsigned long) &(struct soc_mixer_control) \
{.min = xmin, .max = xmax} }
-struct omap_mcbsp_data {
- unsigned int bus_id;
- struct omap_mcbsp_reg_cfg regs;
- unsigned int fmt;
- /*
- * Flags indicating is the bus already activated and configured by
- * another substream
- */
- int active;
- int configured;
- unsigned int in_freq;
- int clk_div;
- int wlen;
+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 struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
-
/*
* Stream DMA parameters. DMA request line and port address are set runtime
* since they are different between OMAP1 and later OMAPs
*/
-static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2];
-
-static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
+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_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
- struct omap_pcm_dma_data *dma_data;
- int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
int words;
- dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
- /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
- if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
- /*
- * Configure McBSP threshold based on either:
- * packet_size, when the sDMA is in packet mode, or
- * based on the period size.
- */
- if (dma_data->packet_size)
- words = dma_data->packet_size;
- else
- words = snd_pcm_lib_period_bytes(substream) /
- (mcbsp_data->wlen / 8);
+ /*
+ * 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_data->bus_id, words);
+ omap_mcbsp_set_tx_threshold(mcbsp, words);
else
- omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words);
+ omap_mcbsp_set_rx_threshold(mcbsp, words);
}
static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
@@ -109,12 +96,12 @@ static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
SNDRV_PCM_HW_PARAM_BUFFER_SIZE);
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
- struct omap_mcbsp_data *mcbsp_data = rule->private;
+ struct omap_mcbsp *mcbsp = rule->private;
struct snd_interval frames;
int size;
snd_interval_any(&frames);
- size = omap_mcbsp_get_fifo_size(mcbsp_data->bus_id);
+ size = mcbsp->pdata->buffer_size;
frames.min = size / channels->min;
frames.integer = 1;
@@ -124,12 +111,11 @@ static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
- struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
- int bus_id = mcbsp_data->bus_id;
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
int err = 0;
if (!cpu_dai->active)
- err = omap_mcbsp_request(bus_id);
+ err = omap_mcbsp_request(mcbsp);
/*
* OMAP3 McBSP FIFO is word structured.
@@ -146,16 +132,18 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
* 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
* 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
*/
- if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
+ if (mcbsp->pdata->buffer_size) {
/*
* Rule for the buffer size. We should not allow
- * smaller buffer than the FIFO size to avoid underruns
+ * smaller buffer than the FIFO size to avoid underruns.
+ * This applies only for the playback stream.
*/
- snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- omap_mcbsp_hwrule_min_buffersize,
- mcbsp_data,
- SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
+ 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,
@@ -168,33 +156,33 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
- struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
if (!cpu_dai->active) {
- omap_mcbsp_free(mcbsp_data->bus_id);
- mcbsp_data->configured = 0;
+ omap_mcbsp_free(mcbsp);
+ mcbsp->configured = 0;
}
}
static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *cpu_dai)
{
- struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- mcbsp_data->active++;
- omap_mcbsp_start(mcbsp_data->bus_id, play, !play);
+ mcbsp->active++;
+ omap_mcbsp_start(mcbsp, play, !play);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- omap_mcbsp_stop(mcbsp_data->bus_id, play, !play);
- mcbsp_data->active--;
+ omap_mcbsp_stop(mcbsp, play, !play);
+ mcbsp->active--;
break;
default:
err = -EINVAL;
@@ -209,14 +197,14 @@ static snd_pcm_sframes_t omap_mcbsp_dai_delay(
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
u16 fifo_use;
snd_pcm_sframes_t delay;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- fifo_use = omap_mcbsp_get_tx_delay(mcbsp_data->bus_id);
+ fifo_use = omap_mcbsp_get_tx_delay(mcbsp);
else
- fifo_use = omap_mcbsp_get_rx_delay(mcbsp_data->bus_id);
+ fifo_use = omap_mcbsp_get_rx_delay(mcbsp);
/*
* Divide the used locations with the channel count to get the
@@ -232,87 +220,63 @@ 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_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
- struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
- struct omap_pcm_dma_data *dma_data;
- int dma, bus_id = mcbsp_data->bus_id;
- int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
+ 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 long port;
unsigned int format, div, framesize, master;
- dma_data = &omap_mcbsp_dai_dma_params[cpu_dai->id][substream->stream];
-
- dma = omap_mcbsp_dma_ch_params(bus_id, substream->stream);
- port = omap_mcbsp_dma_reg_params(bus_id, substream->stream);
+ 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:
- dma_data->data_type = OMAP_DMA_DATA_TYPE_S16;
wlen = 16;
break;
case SNDRV_PCM_FORMAT_S32_LE:
- dma_data->data_type = OMAP_DMA_DATA_TYPE_S32;
wlen = 32;
break;
default:
return -EINVAL;
}
- if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
- dma_data->set_threshold = omap_mcbsp_set_threshold;
- /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
- if (omap_mcbsp_get_dma_op_mode(bus_id) ==
- MCBSP_DMA_MODE_THRESHOLD) {
+ if (mcbsp->pdata->buffer_size) {
+ 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 = omap_mcbsp_get_max_tx_threshold(
- mcbsp_data->bus_id);
+ max_thrsh = mcbsp->max_tx_thres;
else
- max_thrsh = omap_mcbsp_get_max_rx_threshold(
- mcbsp_data->bus_id);
+ max_thrsh = mcbsp->max_rx_thres;
/*
- * If the period contains less or equal number of words,
- * we are using the original threshold mode setup:
- * McBSP threshold = sDMA frame size = period_size
- * Otherwise we switch to sDMA packet mode:
- * McBSP threshold = sDMA packet size
- * sDMA frame size = period size
+ * 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.
*/
- if (period_words > max_thrsh) {
- int divider = 0;
-
- /*
- * 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;
- sync_mode = OMAP_DMA_SYNC_PACKET;
- } else {
- sync_mode = OMAP_DMA_SYNC_FRAME;
- }
+ 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;
}
+ omap_mcbsp_set_threshold(substream, pkt_size);
}
- dma_data->name = substream->stream ? "Audio Capture" : "Audio Playback";
- dma_data->dma_req = dma;
- dma_data->port_addr = port;
- dma_data->sync_mode = sync_mode;
- dma_data->packet_size = pkt_size;
-
- snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+ dma_data->maxburst = pkt_size;
- if (mcbsp_data->configured) {
+ if (mcbsp->configured) {
/* McBSP already configured by another stream */
return 0;
}
@@ -321,8 +285,8 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
regs->xcr2 &= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7));
regs->rcr1 &= ~(RFRLEN1(0x7f) | RWDLEN1(7));
regs->xcr1 &= ~(XFRLEN1(0x7f) | XWDLEN1(7));
- format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
- wpf = channels = params_channels(params);
+ 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 */
@@ -359,10 +323,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
/* In McBSP master modes, FRAME (i.e. sample rate) is generated
* by _counting_ BCLKs. Calculate frame size in BCLKs */
- master = mcbsp_data->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+ master = mcbsp->fmt & SND_SOC_DAIFMT_MASTER_MASK;
if (master == SND_SOC_DAIFMT_CBS_CFS) {
- div = mcbsp_data->clk_div ? mcbsp_data->clk_div : 1;
- framesize = (mcbsp_data->in_freq / div) / params_rate(params);
+ 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 "
@@ -388,9 +352,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
break;
}
- omap_mcbsp_config(bus_id, &mcbsp_data->regs);
- mcbsp_data->wlen = wlen;
- mcbsp_data->configured = 1;
+ omap_mcbsp_config(mcbsp, &mcbsp->cfg_regs);
+ mcbsp->wlen = wlen;
+ mcbsp->configured = 1;
return 0;
}
@@ -402,24 +366,26 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
- struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+ 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_data->configured)
+ if (mcbsp->configured)
return 0;
- mcbsp_data->fmt = fmt;
+ 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 34xx */
- if (!cpu_is_omap34xx() && !cpu_is_omap44xx()) {
+ /* RFIG and XFIG are not defined in 2430 and on OMAP3+ */
+ if (!mcbsp->pdata->has_ccr) {
regs->rcr2 |= RFIG;
regs->xcr2 |= XFIG;
}
- if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
+
+ /* 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;
}
@@ -465,6 +431,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
/* 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;
+ break;
case SND_SOC_DAIFMT_CBM_CFM:
/* McBSP slave */
break;
@@ -504,13 +475,13 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div)
{
- struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
- struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+ 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_data->clk_div = div;
+ mcbsp->clk_div = div;
regs->srgr1 &= ~CLKGDV(0xff);
regs->srgr1 |= CLKGDV(div - 1);
@@ -521,47 +492,39 @@ 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_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
- struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+ 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_data->active) {
- if (freq == mcbsp_data->in_freq)
+ if (mcbsp->active) {
+ if (freq == mcbsp->in_freq)
return 0;
else
return -EBUSY;
}
- /* The McBSP signal muxing functions are only available on McBSP1 */
- if (clk_id == OMAP_MCBSP_CLKR_SRC_CLKR ||
- clk_id == OMAP_MCBSP_CLKR_SRC_CLKX ||
- clk_id == OMAP_MCBSP_FSR_SRC_FSR ||
- clk_id == OMAP_MCBSP_FSR_SRC_FSX)
- if (cpu_class_is_omap1() || mcbsp_data->bus_id != 0)
- return -EINVAL;
-
- mcbsp_data->in_freq = freq;
- regs->srgr2 &= ~CLKSM;
- regs->pcr0 &= ~SCLKME;
+ 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 (cpu_class_is_omap1()) {
+ if (mcbsp_omap1()) {
err = -EINVAL;
break;
}
- err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id,
+ err = omap2_mcbsp_set_clks_src(mcbsp,
MCBSP_CLKS_PRCM_SRC);
break;
case OMAP_MCBSP_SYSCLK_CLKS_EXT:
- if (cpu_class_is_omap1()) {
+ if (mcbsp_omap1()) {
err = 0;
break;
}
- err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id,
+ err = omap2_mcbsp_set_clks_src(mcbsp,
MCBSP_CLKS_PAD_SRC);
break;
@@ -570,28 +533,6 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
case OMAP_MCBSP_SYSCLK_CLKR_EXT:
regs->pcr0 |= SCLKME;
break;
-
-
- case OMAP_MCBSP_CLKR_SRC_CLKR:
- if (cpu_class_is_omap1())
- break;
- omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKR);
- break;
- case OMAP_MCBSP_CLKR_SRC_CLKX:
- if (cpu_class_is_omap1())
- break;
- omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKX);
- break;
- case OMAP_MCBSP_FSR_SRC_FSR:
- if (cpu_class_is_omap1())
- break;
- omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSR);
- break;
- case OMAP_MCBSP_FSR_SRC_FSX:
- if (cpu_class_is_omap1())
- break;
- omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSX);
- break;
default:
err = -ENODEV;
}
@@ -610,15 +551,31 @@ static const struct snd_soc_dai_ops mcbsp_dai_ops = {
.set_sysclk = omap_mcbsp_dai_set_dai_sysclk,
};
-static int mcbsp_dai_probe(struct snd_soc_dai *dai)
+static int omap_mcbsp_probe(struct snd_soc_dai *dai)
{
- mcbsp_data[dai->id].bus_id = dai->id;
- snd_soc_dai_set_drvdata(dai, &mcbsp_data[dai->id].bus_id);
+ 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 = mcbsp_dai_probe,
+ .probe = omap_mcbsp_probe,
+ .remove = omap_mcbsp_remove,
.playback = {
.channels_min = 1,
.channels_max = 16,
@@ -634,6 +591,10 @@ static struct snd_soc_dai_driver omap_mcbsp_dai = {
.ops = &mcbsp_dai_ops,
};
+static const struct snd_soc_component_driver omap_mcbsp_component = {
+ .name = "omap-mcbsp",
+};
+
static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -649,11 +610,13 @@ static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
return 0;
}
-#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(id, channel) \
+#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel) \
static int \
-omap_mcbsp##id##_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \
+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; \
@@ -664,46 +627,41 @@ omap_mcbsp##id##_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \
return -EINVAL; \
\
/* OMAP McBSP implementation uses index values 0..4 */ \
- return omap_st_set_chgain((id)-1, channel, val); \
-}
-
-#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(id, channel) \
+ return omap_st_set_chgain(mcbsp, channel, val); \
+} \
+ \
static int \
-omap_mcbsp##id##_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \
+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_st_get_chgain((id)-1, channel, &chgain)) \
+ if (omap_st_get_chgain(mcbsp, channel, &chgain)) \
return -EAGAIN; \
\
uc->value.integer.value[0] = chgain; \
return 0; \
}
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 0)
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 1)
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 0)
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 1)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 0)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 1)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 0)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 1)
+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 soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
+ 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_st_is_enabled(mc->reg))
+ if (value == omap_st_is_enabled(mcbsp))
return 0;
if (value)
- omap_st_enable(mc->reg);
+ omap_st_enable(mcbsp);
else
- omap_st_disable(mc->reg);
+ omap_st_disable(mcbsp);
return 1;
}
@@ -711,52 +669,51 @@ static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
+ 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_st_is_enabled(mc->reg);
+ ucontrol->value.integer.value[0] = omap_st_is_enabled(mcbsp);
return 0;
}
-static const struct snd_kcontrol_new omap_mcbsp2_st_controls[] = {
- SOC_SINGLE_EXT("McBSP2 Sidetone Switch", 1, 0, 1, 0,
- omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
- OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 0 Volume",
- -32768, 32767,
- omap_mcbsp2_get_st_ch0_volume,
- omap_mcbsp2_set_st_ch0_volume),
- OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 1 Volume",
- -32768, 32767,
- omap_mcbsp2_get_st_ch1_volume,
- omap_mcbsp2_set_st_ch1_volume),
-};
+#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), \
+}
-static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = {
- SOC_SINGLE_EXT("McBSP3 Sidetone Switch", 2, 0, 1, 0,
- omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
- OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 0 Volume",
- -32768, 32767,
- omap_mcbsp3_get_st_ch0_volume,
- omap_mcbsp3_set_st_ch0_volume),
- OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 1 Volume",
- -32768, 32767,
- omap_mcbsp3_get_st_ch1_volume,
- omap_mcbsp3_set_st_ch1_volume),
-};
+OMAP_MCBSP_ST_CONTROLS(2);
+OMAP_MCBSP_ST_CONTROLS(3);
-int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id)
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id)
{
- if (!cpu_is_omap34xx())
- return -ENODEV;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
- switch (mcbsp_id) {
- case 1: /* McBSP 2 */
- return snd_soc_add_controls(codec, omap_mcbsp2_st_controls,
+ 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 2: /* McBSP 3 */
- return snd_soc_add_controls(codec, omap_mcbsp3_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;
}
@@ -764,25 +721,123 @@ int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id)
}
EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
-static __devinit int asoc_mcbsp_probe(struct platform_device *pdev)
+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)
{
- return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai);
+ 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;
+ 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;
+ } 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;
+
+ ret = snd_soc_register_component(&pdev->dev, &omap_mcbsp_component,
+ &omap_mcbsp_dai, 1);
+ if (ret)
+ return ret;
+
+ return omap_pcm_platform_register(&pdev->dev);
}
-static int __devexit asoc_mcbsp_remove(struct platform_device *pdev)
+static int asoc_mcbsp_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&pdev->dev);
+ struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_component(&pdev->dev);
+
+ if (mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+ mcbsp->pdata->ops->free(mcbsp->id);
+
+ omap_mcbsp_sysfs_remove(mcbsp);
+
+ clk_put(mcbsp->fclk);
+
return 0;
}
static struct platform_driver asoc_mcbsp_driver = {
.driver = {
- .name = "omap-mcbsp-dai",
+ .name = "omap-mcbsp",
.owner = THIS_MODULE,
+ .of_match_table = omap_mcbsp_of_match,
},
.probe = asoc_mcbsp_probe,
- .remove = __devexit_p(asoc_mcbsp_remove),
+ .remove = asoc_mcbsp_remove,
};
module_platform_driver(asoc_mcbsp_driver);
@@ -790,3 +845,4 @@ 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
index 65cde9d3807..2e3369c27be 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -32,10 +32,6 @@ enum omap_mcbsp_clksrg_clk {
OMAP_MCBSP_SYSCLK_CLK, /* Internal ICLK */
OMAP_MCBSP_SYSCLK_CLKX_EXT, /* External CLKX pin */
OMAP_MCBSP_SYSCLK_CLKR_EXT, /* External CLKR pin */
- OMAP_MCBSP_CLKR_SRC_CLKR, /* CLKR from CLKR pin */
- OMAP_MCBSP_CLKR_SRC_CLKX, /* CLKR from CLKX pin */
- OMAP_MCBSP_FSR_SRC_FSR, /* FSR from FSR pin */
- OMAP_MCBSP_FSR_SRC_FSX, /* FSR from FSX pin */
};
/* McBSP dividers */
@@ -43,22 +39,6 @@ enum omap_mcbsp_div {
OMAP_MCBSP_CLKGDV, /* Sample rate generator divider */
};
-#if defined(CONFIG_SOC_OMAP2420)
-#define NUM_LINKS 2
-#endif
-#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
-#undef NUM_LINKS
-#define NUM_LINKS 3
-#endif
-#if defined(CONFIG_ARCH_OMAP4)
-#undef NUM_LINKS
-#define NUM_LINKS 4
-#endif
-#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_OMAP2430)
-#undef NUM_LINKS
-#define NUM_LINKS 5
-#endif
-
-int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id);
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id);
#endif
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index 0e25df4fa9e..f0e2ebeab02 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -33,16 +33,21 @@
#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 <sound/omap-pcm.h>
-#include <plat/dma.h>
-#include <plat/omap_hwmod.h>
#include "omap-mcpdm.h"
-#include "omap-pcm.h"
+
+struct mcpdm_link_config {
+ u32 link_mask; /* channel mask for the direction */
+ u32 threshold; /* FIFO threshold */
+};
struct omap_mcpdm {
struct device *dev;
@@ -52,46 +57,30 @@ struct omap_mcpdm {
struct mutex mutex;
- /* channel data */
- u32 dn_channels;
- u32 up_channels;
-
- /* McPDM FIFO thresholds */
- u32 dn_threshold;
- u32 up_threshold;
+ /* 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;
+
+ struct snd_dmaengine_dai_dma_data dma_data[2];
};
/*
* Stream DMA parameters
*/
-static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
- {
- .name = "Audio playback",
- .dma_req = OMAP44XX_DMA_MCPDM_DL,
- .data_type = OMAP_DMA_DATA_TYPE_S32,
- .sync_mode = OMAP_DMA_SYNC_PACKET,
- .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_REG_DN_DATA,
- },
- {
- .name = "Audio capture",
- .dma_req = OMAP44XX_DMA_MCPDM_UP,
- .data_type = OMAP_DMA_DATA_TYPE_S32,
- .sync_mode = OMAP_DMA_SYNC_PACKET,
- .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_REG_UP_DATA,
- },
-};
static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
{
- __raw_writel(val, mcpdm->io_base + reg);
+ writel_relaxed(val, mcpdm->io_base + reg);
}
static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg)
{
- return __raw_readl(mcpdm->io_base + reg);
+ return readl_relaxed(mcpdm->io_base + reg);
}
#ifdef DEBUG
@@ -137,11 +126,12 @@ static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {}
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 |= mcpdm->dn_channels | mcpdm->up_channels;
+ ctrl |= link_mask;
omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
@@ -155,11 +145,12 @@ static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
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 &= ~(mcpdm->dn_channels | mcpdm->up_channels);
+ ctrl &= ~(link_mask);
omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
@@ -195,8 +186,10 @@ static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm)
omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
}
- omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, mcpdm->dn_threshold);
- omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, mcpdm->up_threshold);
+ 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);
@@ -266,16 +259,11 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
mutex_lock(&mcpdm->mutex);
if (!dai->active) {
- /* Enable watch dog for ES above ES 1.0 to avoid saturation */
- if (omap_rev() != OMAP4430_REV_ES1_0) {
- u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+ 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_CTRL, ctrl | MCPDM_WD_EN);
omap_mcpdm_open_streams(mcpdm);
}
-
mutex_unlock(&mcpdm->mutex);
return 0;
@@ -292,6 +280,8 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
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;
}
}
@@ -304,7 +294,8 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
{
struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
int stream = substream->stream;
- struct omap_pcm_dma_data *dma_data;
+ struct snd_dmaengine_dai_dma_data *dma_data;
+ u32 threshold;
int channels;
int link_mask = 0;
@@ -332,19 +323,33 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- dma_data = &omap_mcpdm_dai_dma_params[stream];
+ 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) {
- mcpdm->dn_channels = link_mask << 3;
- dma_data->packet_size =
- (MCPDM_DN_THRES_MAX - mcpdm->dn_threshold) * channels;
+ 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;
} else {
- mcpdm->up_channels = link_mask << 0;
- dma_data->packet_size = mcpdm->up_threshold * channels;
+ /* 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;
}
- snd_soc_dai_set_dma_data(dai, substream, dma_data);
+ /* 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;
}
@@ -357,6 +362,11 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
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;
@@ -380,7 +390,7 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
pm_runtime_get_sync(mcpdm->dev);
omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00);
- ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler,
+ ret = devm_request_irq(mcpdm->dev, mcpdm->irq, omap_mcpdm_irq_handler,
0, "McPDM", (void *)mcpdm);
pm_runtime_put_sync(mcpdm->dev);
@@ -391,8 +401,14 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
}
/* Configure McPDM threshold values */
- mcpdm->dn_threshold = 2;
- mcpdm->up_threshold = MCPDM_UP_THRES_MAX - 3;
+ 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;
}
@@ -400,7 +416,6 @@ 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);
return 0;
@@ -419,16 +434,22 @@ static struct snd_soc_dai_driver omap_mcpdm_dai = {
.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)
{
@@ -438,13 +459,13 @@ void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
}
EXPORT_SYMBOL_GPL(omap_mcpdm_configure_dn_offsets);
-static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
+static int asoc_mcpdm_probe(struct platform_device *pdev)
{
struct omap_mcpdm *mcpdm;
struct resource *res;
- int ret = 0;
+ int ret;
- mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL);
+ mcpdm = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcpdm), GFP_KERNEL);
if (!mcpdm)
return -ENOMEM;
@@ -452,71 +473,55 @@ static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
mutex_init(&mcpdm->mutex);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "no resource\n");
- goto err_res;
- }
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
+ if (res == NULL)
+ return -ENOMEM;
- if (!request_mem_region(res->start, resource_size(res), "McPDM")) {
- ret = -EBUSY;
- goto err_res;
- }
+ mcpdm->dma_data[0].addr = res->start + MCPDM_REG_DN_DATA;
+ mcpdm->dma_data[1].addr = res->start + MCPDM_REG_UP_DATA;
- mcpdm->io_base = ioremap(res->start, resource_size(res));
- if (!mcpdm->io_base) {
- ret = -ENOMEM;
- goto err_iomap;
- }
+ 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) {
- ret = mcpdm->irq;
- goto err_irq;
- }
+ if (mcpdm->irq < 0)
+ return mcpdm->irq;
mcpdm->dev = &pdev->dev;
- ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
- if (!ret)
- return 0;
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &omap_mcpdm_component,
+ &omap_mcpdm_dai, 1);
+ if (ret)
+ return ret;
-err_irq:
- iounmap(mcpdm->io_base);
-err_iomap:
- release_mem_region(res->start, resource_size(res));
-err_res:
- kfree(mcpdm);
- return ret;
+ return omap_pcm_platform_register(&pdev->dev);
}
-static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
-{
- struct omap_mcpdm *mcpdm = platform_get_drvdata(pdev);
- struct resource *res;
-
- snd_soc_unregister_dai(&pdev->dev);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- iounmap(mcpdm->io_base);
- release_mem_region(res->start, resource_size(res));
-
- kfree(mcpdm);
- return 0;
-}
+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",
.owner = THIS_MODULE,
+ .of_match_table = omap_mcpdm_of_match,
},
.probe = asoc_mcpdm_probe,
- .remove = __devexit_p(asoc_mcpdm_remove),
};
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-pcm.c b/sound/soc/omap/omap-pcm.c
index a59bd352d34..8d809f8509c 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -25,13 +25,18 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/omap-dma.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
#include <sound/soc.h>
-#include <plat/dma.h>
-#include "omap-pcm.h"
+#ifdef CONFIG_ARCH_OMAP1
+#define pcm_omap1510() cpu_is_omap1510()
+#else
+#define pcm_omap1510() 0
+#endif
static const struct snd_pcm_hardware omap_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
@@ -40,8 +45,6 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
.period_bytes_min = 32,
.period_bytes_max = 64 * 1024,
.periods_min = 2,
@@ -49,61 +52,15 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
.buffer_bytes_max = 128 * 1024,
};
-struct omap_runtime_data {
- spinlock_t lock;
- struct omap_pcm_dma_data *dma_data;
- int dma_ch;
- int period_index;
-};
-
-static void omap_pcm_dma_irq(int ch, u16 stat, void *data)
-{
- struct snd_pcm_substream *substream = data;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct omap_runtime_data *prtd = runtime->private_data;
- unsigned long flags;
-
- if ((cpu_is_omap1510())) {
- /*
- * OMAP1510 doesn't fully support DMA progress counter
- * and there is no software emulation implemented yet,
- * so have to maintain our own progress counters
- * that can be used by omap_pcm_pointer() instead.
- */
- spin_lock_irqsave(&prtd->lock, flags);
- if ((stat == OMAP_DMA_LAST_IRQ) &&
- (prtd->period_index == runtime->periods - 1)) {
- /* we are in sync, do nothing */
- spin_unlock_irqrestore(&prtd->lock, flags);
- return;
- }
- if (prtd->period_index >= 0) {
- if (stat & OMAP_DMA_BLOCK_IRQ) {
- /* end of buffer reached, loop back */
- prtd->period_index = 0;
- } else if (stat & OMAP_DMA_LAST_IRQ) {
- /* update the counter for the last period */
- prtd->period_index = runtime->periods - 1;
- } else if (++prtd->period_index >= runtime->periods) {
- /* end of buffer missed? loop back */
- prtd->period_index = 0;
- }
- }
- spin_unlock_irqrestore(&prtd->lock, flags);
- }
-
- snd_pcm_period_elapsed(substream);
-}
-
/* this may get called several times by oss emulation */
static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct omap_runtime_data *prtd = runtime->private_data;
struct omap_pcm_dma_data *dma_data;
-
+ struct dma_slave_config config;
+ struct dma_chan *chan;
int err = 0;
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
@@ -116,200 +73,65 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
runtime->dma_bytes = params_buffer_bytes(params);
- if (prtd->dma_data)
- return 0;
- prtd->dma_data = dma_data;
- err = omap_request_dma(dma_data->dma_req, dma_data->name,
- omap_pcm_dma_irq, substream, &prtd->dma_ch);
- if (!err) {
- /*
- * Link channel with itself so DMA doesn't need any
- * reprogramming while looping the buffer
- */
- omap_dma_link_lch(prtd->dma_ch, prtd->dma_ch);
- }
+ chan = snd_dmaengine_pcm_get_chan(substream);
+ if (!chan)
+ return -EINVAL;
- return err;
-}
-
-static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct omap_runtime_data *prtd = runtime->private_data;
-
- if (prtd->dma_data == NULL)
- return 0;
+ /* fills in addr_width and direction */
+ err = snd_hwparams_to_dma_slave_config(substream, params, &config);
+ if (err)
+ return err;
- omap_dma_unlink_lch(prtd->dma_ch, prtd->dma_ch);
- omap_free_dma(prtd->dma_ch);
- prtd->dma_data = NULL;
+ snd_dmaengine_pcm_set_config_from_dai_data(substream,
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
+ &config);
- snd_pcm_set_runtime_buffer(substream, NULL);
-
- return 0;
+ return dmaengine_slave_config(chan, &config);
}
-static int omap_pcm_prepare(struct snd_pcm_substream *substream)
+static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct omap_runtime_data *prtd = runtime->private_data;
- struct omap_pcm_dma_data *dma_data = prtd->dma_data;
- struct omap_dma_channel_params dma_params;
- int bytes;
-
- /* return if this is a bufferless transfer e.g.
- * codec <--> BT codec or GSM modem -- lg FIXME */
- if (!prtd->dma_data)
- return 0;
-
- memset(&dma_params, 0, sizeof(dma_params));
- dma_params.data_type = dma_data->data_type;
- dma_params.trigger = dma_data->dma_req;
- dma_params.sync_mode = dma_data->sync_mode;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- dma_params.src_amode = OMAP_DMA_AMODE_POST_INC;
- dma_params.dst_amode = OMAP_DMA_AMODE_CONSTANT;
- dma_params.src_or_dst_synch = OMAP_DMA_DST_SYNC;
- dma_params.src_start = runtime->dma_addr;
- dma_params.dst_start = dma_data->port_addr;
- dma_params.dst_port = OMAP_DMA_PORT_MPUI;
- dma_params.dst_fi = dma_data->packet_size;
- } else {
- dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT;
- dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC;
- dma_params.src_or_dst_synch = OMAP_DMA_SRC_SYNC;
- dma_params.src_start = dma_data->port_addr;
- dma_params.dst_start = runtime->dma_addr;
- dma_params.src_port = OMAP_DMA_PORT_MPUI;
- dma_params.src_fi = dma_data->packet_size;
- }
- /*
- * Set DMA transfer frame size equal to ALSA period size and frame
- * count as no. of ALSA periods. Then with DMA frame interrupt enabled,
- * we can transfer the whole ALSA buffer with single DMA transfer but
- * still can get an interrupt at each period bounary
- */
- bytes = snd_pcm_lib_period_bytes(substream);
- dma_params.elem_count = bytes >> dma_data->data_type;
- dma_params.frame_count = runtime->periods;
- omap_set_dma_params(prtd->dma_ch, &dma_params);
-
- if ((cpu_is_omap1510()))
- omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ |
- OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ);
- else if (!substream->runtime->no_period_wakeup)
- omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ);
- else {
- /*
- * No period wakeup:
- * we need to disable BLOCK_IRQ, which is enabled by the omap
- * dma core at request dma time.
- */
- omap_disable_dma_irq(prtd->dma_ch, OMAP_DMA_BLOCK_IRQ);
- }
-
- if (!(cpu_class_is_omap1())) {
- omap_set_dma_src_burst_mode(prtd->dma_ch,
- OMAP_DMA_DATA_BURST_16);
- omap_set_dma_dest_burst_mode(prtd->dma_ch,
- OMAP_DMA_DATA_BURST_16);
- }
-
+ snd_pcm_set_runtime_buffer(substream, NULL);
return 0;
}
-static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct omap_runtime_data *prtd = runtime->private_data;
- struct omap_pcm_dma_data *dma_data = prtd->dma_data;
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&prtd->lock, flags);
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- prtd->period_index = 0;
- /* Configure McBSP internal buffer usage */
- if (dma_data->set_threshold)
- dma_data->set_threshold(substream);
-
- omap_start_dma(prtd->dma_ch);
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- prtd->period_index = -1;
- omap_stop_dma(prtd->dma_ch);
- break;
- default:
- ret = -EINVAL;
- }
- spin_unlock_irqrestore(&prtd->lock, flags);
-
- return ret;
-}
-
static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct omap_runtime_data *prtd = runtime->private_data;
- dma_addr_t ptr;
snd_pcm_uframes_t offset;
- if (cpu_is_omap1510()) {
- offset = prtd->period_index * runtime->period_size;
- } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- ptr = omap_get_dma_dst_pos(prtd->dma_ch);
- offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
- } else {
- ptr = omap_get_dma_src_pos(prtd->dma_ch);
- offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
- }
-
- if (offset >= runtime->buffer_size)
- offset = 0;
+ if (pcm_omap1510())
+ offset = snd_dmaengine_pcm_pointer_no_residue(substream);
+ else
+ offset = snd_dmaengine_pcm_pointer(substream);
return offset;
}
static int omap_pcm_open(struct snd_pcm_substream *substream)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct omap_runtime_data *prtd;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_dmaengine_dai_dma_data *dma_data;
int ret;
snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware);
- /* Ensure that buffer size is a multiple of period size */
- ret = snd_pcm_hw_constraint_integer(runtime,
- SNDRV_PCM_HW_PARAM_PERIODS);
- if (ret < 0)
- goto out;
+ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
- prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
- if (prtd == NULL) {
- ret = -ENOMEM;
- goto out;
- }
- spin_lock_init(&prtd->lock);
- runtime->private_data = prtd;
+ /* DT boot: filter_data is the DMA name */
+ if (rtd->cpu_dai->dev->of_node) {
+ struct dma_chan *chan;
-out:
+ chan = dma_request_slave_channel(rtd->cpu_dai->dev,
+ dma_data->filter_data);
+ ret = snd_dmaengine_pcm_open(substream, chan);
+ } else {
+ ret = snd_dmaengine_pcm_open_request_chan(substream,
+ omap_dma_filter_fn,
+ dma_data->filter_data);
+ }
return ret;
}
-static int omap_pcm_close(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- kfree(runtime->private_data);
- return 0;
-}
-
static int omap_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
@@ -323,18 +145,15 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream,
static struct snd_pcm_ops omap_pcm_ops = {
.open = omap_pcm_open,
- .close = omap_pcm_close,
+ .close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = omap_pcm_hw_params,
.hw_free = omap_pcm_hw_free,
- .prepare = omap_pcm_prepare,
- .trigger = omap_pcm_trigger,
+ .trigger = snd_dmaengine_pcm_trigger,
.pointer = omap_pcm_pointer,
.mmap = omap_pcm_mmap,
};
-static u64 omap_pcm_dmamask = DMA_BIT_MASK(64);
-
static int omap_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
int stream)
{
@@ -379,12 +198,11 @@ static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
- int ret = 0;
+ int ret;
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &omap_pcm_dmamask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(64);
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(64));
+ if (ret)
+ return ret;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = omap_pcm_preallocate_dma_buffer(pcm,
@@ -401,6 +219,10 @@ static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd)
}
out:
+ /* free preallocated buffers in case of error */
+ if (ret)
+ omap_pcm_free_dma_buffers(pcm);
+
return ret;
}
@@ -410,29 +232,11 @@ static struct snd_soc_platform_driver omap_soc_platform = {
.pcm_free = omap_pcm_free_dma_buffers,
};
-static __devinit int omap_pcm_probe(struct platform_device *pdev)
+int omap_pcm_platform_register(struct device *dev)
{
- return snd_soc_register_platform(&pdev->dev,
- &omap_soc_platform);
+ return devm_snd_soc_register_platform(dev, &omap_soc_platform);
}
-
-static int __devexit omap_pcm_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
-}
-
-static struct platform_driver omap_pcm_driver = {
- .driver = {
- .name = "omap-pcm-audio",
- .owner = THIS_MODULE,
- },
-
- .probe = omap_pcm_probe,
- .remove = __devexit_p(omap_pcm_remove),
-};
-
-module_platform_driver(omap_pcm_driver);
+EXPORT_SYMBOL_GPL(omap_pcm_platform_register);
MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
MODULE_DESCRIPTION("OMAP PCM DMA module");
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
deleted file mode 100644
index f95fe306417..00000000000
--- a/sound/soc/omap/omap-pcm.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * omap-pcm.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_PCM_H__
-#define __OMAP_PCM_H__
-
-struct omap_pcm_dma_data {
- char *name; /* stream identifier */
- int dma_req; /* DMA request line */
- unsigned long port_addr; /* transmit/receive register */
- void (*set_threshold)(struct snd_pcm_substream *substream);
- int data_type; /* data type 8,16,32 */
- int sync_mode; /* DMA sync mode */
- int packet_size; /* packet size only in PACKET mode */
-};
-
-#endif
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c
new file mode 100644
index 00000000000..f8a6adc2d81
--- /dev/null
+++ b/sound/soc/omap/omap-twl4030.c
@@ -0,0 +1,390 @@
+/*
+ * 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;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_card *card = rtd->card;
+ unsigned int fmt;
+ int ret;
+
+ 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;
+ }
+
+ /* Set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+ if (ret < 0) {
+ dev_err(card->dev, "can't set codec DAI configuration\n");
+ return ret;
+ }
+
+ /* Set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (ret < 0) {
+ dev_err(card->dev, "can't set cpu DAI configuration\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static 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_codec *codec = rtd->codec;
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dapm_context *dapm = &codec->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_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
+ &priv->hs_jack);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_pins(&priv->hs_jack,
+ ARRAY_SIZE(hs_jack_pins),
+ 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;
+}
+
+static int omap_twl4030_card_remove(struct snd_soc_card *card)
+{
+ struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
+
+ if (priv->jack_detect > 0)
+ snd_soc_jack_free_gpios(&priv->hs_jack,
+ ARRAY_SIZE(hs_jack_gpios),
+ hs_jack_gpios);
+
+ return 0;
+}
+
+/* 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.2",
+ .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,
+ .remove = omap_twl4030_card_remove,
+ .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",
+ .owner = THIS_MODULE,
+ .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/omap3beagle.c b/sound/soc/omap/omap3beagle.c
deleted file mode 100644
index 3357dcc47ed..00000000000
--- a/sound/soc/omap/omap3beagle.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * omap3beagle.c -- SoC audio for OMAP3 Beagle
- *
- * Author: Steve Sakoman <steve@sakoman.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/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <plat/mcbsp.h>
-
-#include "omap-mcbsp.h"
-#include "omap-pcm.h"
-
-static int omap3beagle_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;
- unsigned int fmt;
- int ret;
-
- 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;
- }
-
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, fmt);
- if (ret < 0) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
- if (ret < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return 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) {
- printk(KERN_ERR "can't set codec system clock\n");
- return ret;
- }
-
- return 0;
-}
-
-static struct snd_soc_ops omap3beagle_ops = {
- .hw_params = omap3beagle_hw_params,
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link omap3beagle_dai = {
- .name = "TWL4030",
- .stream_name = "TWL4030",
- .cpu_dai_name = "omap-mcbsp-dai.1",
- .platform_name = "omap-pcm-audio",
- .codec_dai_name = "twl4030-hifi",
- .codec_name = "twl4030-codec",
- .ops = &omap3beagle_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_omap3beagle = {
- .name = "omap3beagle",
- .owner = THIS_MODULE,
- .dai_link = &omap3beagle_dai,
- .num_links = 1,
-};
-
-static struct platform_device *omap3beagle_snd_device;
-
-static int __init omap3beagle_soc_init(void)
-{
- int ret;
-
- if (!(machine_is_omap3_beagle() || machine_is_devkit8000()))
- return -ENODEV;
- pr_info("OMAP3 Beagle/Devkit8000 SoC init\n");
-
- omap3beagle_snd_device = platform_device_alloc("soc-audio", -1);
- if (!omap3beagle_snd_device) {
- printk(KERN_ERR "Platform device allocation failed\n");
- return -ENOMEM;
- }
-
- platform_set_drvdata(omap3beagle_snd_device, &snd_soc_omap3beagle);
-
- ret = platform_device_add(omap3beagle_snd_device);
- if (ret)
- goto err1;
-
- return 0;
-
-err1:
- printk(KERN_ERR "Unable to add platform device\n");
- platform_device_put(omap3beagle_snd_device);
-
- return ret;
-}
-
-static void __exit omap3beagle_soc_exit(void)
-{
- platform_device_unregister(omap3beagle_snd_device);
-}
-
-module_init(omap3beagle_soc_init);
-module_exit(omap3beagle_soc_exit);
-
-MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>");
-MODULE_DESCRIPTION("ALSA SoC OMAP3 Beagle");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
deleted file mode 100644
index 071fcb09b8b..00000000000
--- a/sound/soc/omap/omap3evm.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * omap3evm.c -- ALSA SoC support for OMAP3 EVM
- *
- * Author: Anuj Aggarwal <anuj.aggarwal@ti.com>
- *
- * Based on sound/soc/omap/beagle.c by Steve Sakoman
- *
- * Copyright (C) 2008 Texas Instruments, Incorporated
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
- * whether express or implied; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <plat/mcbsp.h>
-
-#include "omap-mcbsp.h"
-#include "omap-pcm.h"
-
-static int omap3evm_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 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) {
- printk(KERN_ERR "Can't set codec system clock\n");
- return ret;
- }
-
- return 0;
-}
-
-static struct snd_soc_ops omap3evm_ops = {
- .hw_params = omap3evm_hw_params,
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link omap3evm_dai = {
- .name = "TWL4030",
- .stream_name = "TWL4030",
- .cpu_dai_name = "omap-mcbsp-dai.1",
- .codec_dai_name = "twl4030-hifi",
- .platform_name = "omap-pcm-audio",
- .codec_name = "twl4030-codec",
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
- .ops = &omap3evm_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_omap3evm = {
- .name = "omap3evm",
- .owner = THIS_MODULE,
- .dai_link = &omap3evm_dai,
- .num_links = 1,
-};
-
-static struct platform_device *omap3evm_snd_device;
-
-static int __init omap3evm_soc_init(void)
-{
- int ret;
-
- if (!machine_is_omap3evm())
- return -ENODEV;
- pr_info("OMAP3 EVM SoC init\n");
-
- omap3evm_snd_device = platform_device_alloc("soc-audio", -1);
- if (!omap3evm_snd_device) {
- printk(KERN_ERR "Platform device allocation failed\n");
- return -ENOMEM;
- }
-
- platform_set_drvdata(omap3evm_snd_device, &snd_soc_omap3evm);
- ret = platform_device_add(omap3evm_snd_device);
- if (ret)
- goto err1;
-
- return 0;
-
-err1:
- printk(KERN_ERR "Unable to add platform device\n");
- platform_device_put(omap3evm_snd_device);
-
- return ret;
-}
-
-static void __exit omap3evm_soc_exit(void)
-{
- platform_device_unregister(omap3evm_snd_device);
-}
-
-module_init(omap3evm_soc_init);
-module_exit(omap3evm_soc_exit);
-
-MODULE_AUTHOR("Anuj Aggarwal <anuj.aggarwal@ti.com>");
-MODULE_DESCRIPTION("ALSA SoC OMAP3 EVM");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index 07794bd1095..076bec606d7 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -31,10 +31,9 @@
#include <sound/soc.h>
#include <asm/mach-types.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "omap-mcbsp.h"
-#include "omap-pcm.h"
#define OMAP3_PANDORA_DAC_POWER_GPIO 118
#define OMAP3_PANDORA_AMP_POWER_GPIO 14
@@ -80,12 +79,18 @@ static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
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)) {
- regulator_enable(omap3pandora_dac_reg);
+ 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 {
@@ -116,7 +121,7 @@ static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
* |A| <~~clk~~+
* |P| <--- TWL4030 <--------- Line In and MICs
*/
-static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = {
+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),
@@ -125,37 +130,32 @@ static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = {
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_LINE("Line Out", NULL),
-};
-static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = {
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_out_map[] = {
+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"},
-};
-static const struct snd_soc_dapm_route omap3pandora_in_map[] = {
{"AUXL", NULL, "Line In"},
{"AUXR", NULL, "Line In"},
- {"MAINMIC", NULL, "Mic Bias 1"},
- {"Mic Bias 1", NULL, "Mic (internal)"},
+ {"MAINMIC", NULL, "Mic (internal)"},
+ {"Mic (internal)", NULL, "Mic Bias 1"},
- {"SUBMIC", NULL, "Mic Bias 2"},
- {"Mic Bias 2", NULL, "Mic (external)"},
+ {"SUBMIC", NULL, "Mic (external)"},
+ {"Mic (external)", NULL, "Mic Bias 2"},
};
static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
/* All TWL4030 output pins are floating */
snd_soc_dapm_nc_pin(dapm, "EARPIECE");
@@ -169,20 +169,13 @@ static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "HFR");
snd_soc_dapm_nc_pin(dapm, "VIBRA");
- ret = snd_soc_dapm_new_controls(dapm, omap3pandora_out_dapm_widgets,
- ARRAY_SIZE(omap3pandora_out_dapm_widgets));
- if (ret < 0)
- return ret;
-
- return snd_soc_dapm_add_routes(dapm, omap3pandora_out_map,
- ARRAY_SIZE(omap3pandora_out_map));
+ return 0;
}
static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
/* Not comnnected */
snd_soc_dapm_nc_pin(dapm, "HSMIC");
@@ -190,13 +183,7 @@ static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
- ret = snd_soc_dapm_new_controls(dapm, omap3pandora_in_dapm_widgets,
- ARRAY_SIZE(omap3pandora_in_dapm_widgets));
- if (ret < 0)
- return ret;
-
- return snd_soc_dapm_add_routes(dapm, omap3pandora_in_map,
- ARRAY_SIZE(omap3pandora_in_map));
+ return 0;
}
static struct snd_soc_ops omap3pandora_ops = {
@@ -208,9 +195,9 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
{
.name = "PCM1773",
.stream_name = "HiFi Out",
- .cpu_dai_name = "omap-mcbsp-dai.1",
+ .cpu_dai_name = "omap-mcbsp.2",
.codec_dai_name = "twl4030-hifi",
- .platform_name = "omap-pcm-audio",
+ .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,
@@ -219,9 +206,9 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
}, {
.name = "TWL4030",
.stream_name = "Line/Mic In",
- .cpu_dai_name = "omap-mcbsp-dai.3",
+ .cpu_dai_name = "omap-mcbsp.4",
.codec_dai_name = "twl4030-hifi",
- .platform_name = "omap-pcm-audio",
+ .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,
@@ -236,6 +223,11 @@ static struct snd_soc_card snd_soc_card_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;
diff --git a/sound/soc/omap/omap4-hdmi-card.c b/sound/soc/omap/omap4-hdmi-card.c
deleted file mode 100644
index 28d689b2714..00000000000
--- a/sound/soc/omap/omap4-hdmi-card.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * omap4-hdmi-card.c
- *
- * OMAP ALSA SoC machine driver for TI OMAP4 HDMI
- * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
- * Author: Ricardo Neri <ricardo.neri@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/module.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <asm/mach-types.h>
-#include <video/omapdss.h>
-
-#define DRV_NAME "omap4-hdmi-audio"
-
-static int omap4_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- int i;
- struct omap_overlay_manager *mgr = NULL;
- struct device *dev = substream->pcm->card->dev;
-
- /* Find DSS HDMI device */
- for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
- mgr = omap_dss_get_overlay_manager(i);
- if (mgr && mgr->device
- && mgr->device->type == OMAP_DISPLAY_TYPE_HDMI)
- break;
- }
-
- if (i == omap_dss_get_num_overlay_managers()) {
- dev_err(dev, "HDMI display device not found!\n");
- return -ENODEV;
- }
-
- /* Make sure HDMI is power-on to avoid L3 interconnect errors */
- if (mgr->device->state != OMAP_DSS_DISPLAY_ACTIVE) {
- dev_err(dev, "HDMI display is not active!\n");
- return -EIO;
- }
-
- return 0;
-}
-
-static struct snd_soc_ops omap4_hdmi_dai_ops = {
- .hw_params = omap4_hdmi_dai_hw_params,
-};
-
-static struct snd_soc_dai_link omap4_hdmi_dai = {
- .name = "HDMI",
- .stream_name = "HDMI",
- .cpu_dai_name = "hdmi-audio-dai",
- .platform_name = "omap-pcm-audio",
- .codec_name = "omapdss_hdmi",
- .codec_dai_name = "hdmi-audio-codec",
- .ops = &omap4_hdmi_dai_ops,
-};
-
-static struct snd_soc_card snd_soc_omap4_hdmi = {
- .name = "OMAP4HDMI",
- .owner = THIS_MODULE,
- .dai_link = &omap4_hdmi_dai,
- .num_links = 1,
-};
-
-static __devinit int omap4_hdmi_probe(struct platform_device *pdev)
-{
- struct snd_soc_card *card = &snd_soc_omap4_hdmi;
- 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 __devexit omap4_hdmi_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
-
- snd_soc_unregister_card(card);
- card->dev = NULL;
- return 0;
-}
-
-static struct platform_driver omap4_hdmi_driver = {
- .driver = {
- .name = "omap4-hdmi-audio",
- .owner = THIS_MODULE,
- },
- .probe = omap4_hdmi_probe,
- .remove = __devexit_p(omap4_hdmi_remove),
-};
-
-module_platform_driver(omap4_hdmi_driver);
-
-MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
-MODULE_DESCRIPTION("OMAP4 HDMI machine ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index d859b597e7e..aa4053bf671 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -28,13 +28,11 @@
#include <sound/soc.h>
#include <asm/mach-types.h>
-#include <mach/hardware.h>
#include <linux/gpio.h>
#include <linux/module.h>
-#include <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "omap-mcbsp.h"
-#include "omap-pcm.h"
#include "../codecs/tlv320aic23.h"
#define CODEC_CLOCK 12000000
@@ -96,9 +94,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
static struct snd_soc_dai_link osk_dai = {
.name = "TLV320AIC23",
.stream_name = "AIC23",
- .cpu_dai_name = "omap-mcbsp-dai.0",
+ .cpu_dai_name = "omap-mcbsp.1",
.codec_dai_name = "tlv320aic23-hifi",
- .platform_name = "omap-pcm-audio",
+ .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,
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
deleted file mode 100644
index 2ee889c5025..00000000000
--- a/sound/soc/omap/overo.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * overo.c -- SoC audio for Gumstix Overo
- *
- * Author: Steve Sakoman <steve@sakoman.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/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <plat/mcbsp.h>
-
-#include "omap-mcbsp.h"
-#include "omap-pcm.h"
-
-static int overo_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 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) {
- printk(KERN_ERR "can't set codec system clock\n");
- return ret;
- }
-
- return 0;
-}
-
-static struct snd_soc_ops overo_ops = {
- .hw_params = overo_hw_params,
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link overo_dai = {
- .name = "TWL4030",
- .stream_name = "TWL4030",
- .cpu_dai_name = "omap-mcbsp-dai.1",
- .codec_dai_name = "twl4030-hifi",
- .platform_name = "omap-pcm-audio",
- .codec_name = "twl4030-codec",
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
- .ops = &overo_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_card_overo = {
- .name = "overo",
- .owner = THIS_MODULE,
- .dai_link = &overo_dai,
- .num_links = 1,
-};
-
-static struct platform_device *overo_snd_device;
-
-static int __init overo_soc_init(void)
-{
- int ret;
-
- if (!(machine_is_overo() || machine_is_cm_t35())) {
- pr_debug("Incomatible machine!\n");
- return -ENODEV;
- }
- printk(KERN_INFO "overo SoC init\n");
-
- overo_snd_device = platform_device_alloc("soc-audio", -1);
- if (!overo_snd_device) {
- printk(KERN_ERR "Platform device allocation failed\n");
- return -ENOMEM;
- }
-
- platform_set_drvdata(overo_snd_device, &snd_soc_card_overo);
-
- ret = platform_device_add(overo_snd_device);
- if (ret)
- goto err1;
-
- return 0;
-
-err1:
- printk(KERN_ERR "Unable to add platform device\n");
- platform_device_put(overo_snd_device);
-
- return ret;
-}
-module_init(overo_soc_init);
-
-static void __exit overo_soc_exit(void)
-{
- platform_device_unregister(overo_snd_device);
-}
-module_exit(overo_soc_exit);
-
-MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>");
-MODULE_DESCRIPTION("ALSA SoC overo");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index fada6ef43ee..943922c79f7 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -26,27 +26,18 @@
#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 <plat/mcbsp.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "../codecs/tpa6130a2.h"
#include <asm/mach-types.h>
#include "omap-mcbsp.h"
-#include "omap-pcm.h"
-
-#define RX51_TVOUT_SEL_GPIO 40
-#define RX51_JACK_DETECT_GPIO 177
-#define RX51_ECI_SW_GPIO 182
-/*
- * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This
- * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c
- */
-#define RX51_SPEAKER_AMP_TWL_GPIO (192 + 7)
enum {
RX51_JACK_DISABLED,
@@ -55,13 +46,21 @@ enum {
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_codec *codec)
+static void rx51_ext_control(struct snd_soc_dapm_context *dapm)
{
- struct snd_soc_dapm_context *dapm = &codec->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) {
@@ -76,37 +75,41 @@ static void rx51_ext_control(struct snd_soc_codec *codec)
break;
}
+ snd_soc_dapm_mutex_lock(dapm);
+
if (rx51_spk_func)
- snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
else
- snd_soc_dapm_disable_pin(dapm, "Ext Spk");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
if (rx51_dmic_func)
- snd_soc_dapm_enable_pin(dapm, "DMic");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "DMic");
else
- snd_soc_dapm_disable_pin(dapm, "DMic");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "DMic");
if (hp)
- snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
else
- snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
if (hs)
- snd_soc_dapm_enable_pin(dapm, "HS Mic");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic");
else
- snd_soc_dapm_disable_pin(dapm, "HS Mic");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic");
- gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout);
+ gpiod_set_value(pdata->tvout_selection_gpio, tvout);
- snd_soc_dapm_sync(dapm);
+ 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_codec *codec = rtd->codec;
+ struct snd_soc_card *card = rtd->card;
snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
- rx51_ext_control(codec);
+ rx51_ext_control(&card->dapm);
return 0;
}
@@ -138,13 +141,13 @@ static int rx51_get_spk(struct snd_kcontrol *kcontrol,
static int rx51_set_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
if (rx51_spk_func == ucontrol->value.integer.value[0])
return 0;
rx51_spk_func = ucontrol->value.integer.value[0];
- rx51_ext_control(codec);
+ rx51_ext_control(&card->dapm);
return 1;
}
@@ -152,10 +155,12 @@ static int rx51_set_spk(struct snd_kcontrol *kcontrol,
static int rx51_spk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
- if (SND_SOC_DAPM_EVENT_ON(event))
- gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 1);
- else
- gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 0);
+ 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;
}
@@ -184,13 +189,13 @@ static int rx51_get_input(struct snd_kcontrol *kcontrol,
static int rx51_set_input(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
if (rx51_dmic_func == ucontrol->value.integer.value[0])
return 0;
rx51_dmic_func = ucontrol->value.integer.value[0];
- rx51_ext_control(codec);
+ rx51_ext_control(&card->dapm);
return 1;
}
@@ -206,13 +211,13 @@ static int rx51_get_jack(struct snd_kcontrol *kcontrol,
static int rx51_set_jack(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
if (rx51_jack_func == ucontrol->value.integer.value[0])
return 0;
rx51_jack_func = ucontrol->value.integer.value[0];
- rx51_ext_control(codec);
+ rx51_ext_control(&card->dapm);
return 1;
}
@@ -221,7 +226,6 @@ static struct snd_soc_jack rx51_av_jack;
static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
{
- .gpio = RX51_JACK_DETECT_GPIO,
.name = "avdet-gpio",
.report = SND_JACK_HEADSET,
.invert = 1,
@@ -235,9 +239,6 @@ static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", rx51_hp_event),
SND_SOC_DAPM_MIC("HS Mic", NULL),
SND_SOC_DAPM_LINE("FM Transmitter", NULL),
-};
-
-static const struct snd_soc_dapm_widget aic34_dapm_widgetsb[] = {
SND_SOC_DAPM_SPK("Earphone", NULL),
};
@@ -249,21 +250,21 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"FM Transmitter", NULL, "LLOUT"},
{"FM Transmitter", NULL, "RLOUT"},
- {"DMic Rate 64", NULL, "Mic Bias 2V"},
- {"Mic Bias 2V", NULL, "DMic"},
-};
+ {"DMic Rate 64", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "DMic"},
-static const struct snd_soc_dapm_route audio_mapb[] = {
{"b LINE2R", NULL, "MONO_LOUT"},
{"Earphone", NULL, "b HPLOUT"},
- {"LINE1L", NULL, "b Mic Bias 2.5V"},
- {"b Mic Bias 2.5V", NULL, "HS Mic"}
+ {"LINE1L", NULL, "b Mic Bias"},
+ {"b Mic Bias", NULL, "HS Mic"}
};
-static const char *spk_function[] = {"Off", "On"};
-static const char *input_function[] = {"ADC", "Digital Mic"};
-static const char *jack_function[] = {"Off", "TV-OUT", "Headphone", "Headset"};
+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),
@@ -279,15 +280,15 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = {
SOC_ENUM_EXT("Jack Function", rx51_enum[2],
rx51_get_jack, rx51_set_jack),
SOC_DAPM_PIN_SWITCH("FM Transmitter"),
-};
-
-static const struct snd_kcontrol_new aic34_rx51_controlsb[] = {
SOC_DAPM_PIN_SWITCH("Earphone"),
};
static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_card *card = rtd->card;
+ struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
+
struct snd_soc_dapm_context *dapm = &codec->dapm;
int err;
@@ -296,57 +297,49 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "MIC3R");
snd_soc_dapm_nc_pin(dapm, "LINE1R");
- /* Add RX-51 specific controls */
- err = snd_soc_add_controls(codec, aic34_rx51_controls,
- ARRAY_SIZE(aic34_rx51_controls));
- if (err < 0)
- return err;
-
- /* Add RX-51 specific widgets */
- snd_soc_dapm_new_controls(dapm, aic34_dapm_widgets,
- ARRAY_SIZE(aic34_dapm_widgets));
-
- /* Set up RX-51 specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
err = tpa6130a2_add_controls(codec);
- if (err < 0)
+ if (err < 0) {
+ dev_err(card->dev, "Failed to add TPA6130A2 controls\n");
return err;
+ }
snd_soc_limit_volume(codec, "TPA6130A2 Headphone Playback Volume", 42);
- err = omap_mcbsp_st_add_controls(codec, 1);
- if (err < 0)
+ 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_jack_new(codec, "AV Jack",
SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
&rx51_av_jack);
- if (err)
+ 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;
}
-static int rx51_aic34b_init(struct snd_soc_dapm_context *dapm)
+static int rx51_card_remove(struct snd_soc_card *card)
{
- int err;
-
- err = snd_soc_add_controls(dapm->codec, aic34_rx51_controlsb,
- ARRAY_SIZE(aic34_rx51_controlsb));
- if (err < 0)
- return err;
-
- err = snd_soc_dapm_new_controls(dapm, aic34_dapm_widgetsb,
- ARRAY_SIZE(aic34_dapm_widgetsb));
- if (err < 0)
- return 0;
+ snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios),
+ rx51_av_jack_gpios);
- return snd_soc_dapm_add_routes(dapm, audio_mapb,
- ARRAY_SIZE(audio_mapb));
+ return 0;
}
/* Digital audio interface glue - connects codec <--> CPU */
@@ -354,9 +347,9 @@ static struct snd_soc_dai_link rx51_dai[] = {
{
.name = "TLV320AIC34",
.stream_name = "AIC34",
- .cpu_dai_name = "omap-mcbsp-dai.1",
+ .cpu_dai_name = "omap-mcbsp.2",
.codec_dai_name = "tlv320aic3x-hifi",
- .platform_name = "omap-pcm-audio",
+ .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,
@@ -369,7 +362,6 @@ static struct snd_soc_aux_dev rx51_aux_dev[] = {
{
.name = "TLV320AIC34b",
.codec_name = "tlv320aic3x-codec.2-0019",
- .init = rx51_aic34b_init,
},
};
@@ -384,69 +376,158 @@ static struct snd_soc_codec_conf rx51_codec_conf[] = {
static struct snd_soc_card rx51_sound_card = {
.name = "RX-51",
.owner = THIS_MODULE,
+ .remove = rx51_card_remove,
.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),
-};
-static struct platform_device *rx51_snd_device;
+ .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 __init rx51_soc_init(void)
+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())
+ if (!machine_is_nokia_rx51() && !of_machine_is_compatible("nokia,omap3-n900"))
return -ENODEV;
- err = gpio_request_one(RX51_TVOUT_SEL_GPIO,
- GPIOF_DIR_OUT | GPIOF_INIT_LOW, "tvout_sel");
- if (err)
- goto err_gpio_tvout_sel;
- err = gpio_request_one(RX51_ECI_SW_GPIO,
- GPIOF_DIR_OUT | GPIOF_INIT_HIGH, "eci_sw");
- if (err)
- goto err_gpio_eci_sw;
-
- rx51_snd_device = platform_device_alloc("soc-audio", -1);
- if (!rx51_snd_device) {
- err = -ENOMEM;
- goto err1;
+ 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;
+ }
+
+ /* TODO: tpa6130a2a driver supports only a single instance, so
+ * this driver ignores the headphone-amplifier node for now.
+ * It's already mandatory in the DT binding to be future proof.
+ */
}
- platform_set_drvdata(rx51_snd_device, &rx51_sound_card);
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (pdata == NULL) {
+ dev_err(card->dev, "failed to create private data\n");
+ return -ENOMEM;
+ }
+ snd_soc_card_set_drvdata(card, pdata);
- err = platform_device_add(rx51_snd_device);
- if (err)
- goto err2;
+ pdata->tvout_selection_gpio = devm_gpiod_get(card->dev,
+ "tvout-selection");
+ 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);
+ }
- return 0;
-err2:
- platform_device_put(rx51_snd_device);
-err1:
- gpio_free(RX51_ECI_SW_GPIO);
-err_gpio_eci_sw:
- gpio_free(RX51_TVOUT_SEL_GPIO);
-err_gpio_tvout_sel:
+ err = gpiod_direction_output(pdata->tvout_selection_gpio, 0);
+ if (err) {
+ dev_err(card->dev, "could not setup tvout selection gpio\n");
+ return err;
+ }
- return err;
-}
+ pdata->jack_detection_gpio = devm_gpiod_get(card->dev,
+ "jack-detection");
+ 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);
+ }
-static void __exit rx51_soc_exit(void)
-{
- snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios),
- rx51_av_jack_gpios);
+ pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch");
+ 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);
+ }
+
+ err = gpiod_direction_output(pdata->eci_sw_gpio, 1);
+ if (err) {
+ dev_err(card->dev, "could not setup eci switch gpio\n");
+ return err;
+ }
+
+ pdata->speaker_amp_gpio = devm_gpiod_get(card->dev,
+ "speaker-amplifier");
+ 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 = gpiod_direction_output(pdata->speaker_amp_gpio, 0);
+ if (err) {
+ dev_err(card->dev, "could not setup speaker enable gpio\n");
+ return err;
+ }
- platform_device_unregister(rx51_snd_device);
- gpio_free(RX51_ECI_SW_GPIO);
- gpio_free(RX51_TVOUT_SEL_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;
}
-module_init(rx51_soc_init);
-module_exit(rx51_soc_exit);
+#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",
+ .owner = THIS_MODULE,
+ .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/sdp3430.c b/sound/soc/omap/sdp3430.c
deleted file mode 100644
index 2c850662ea7..00000000000
--- a/sound/soc/omap/sdp3430.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * sdp3430.c -- SoC audio for TI OMAP3430 SDP
- *
- * Author: Misael Lopez Cruz <x0052729@ti.com>
- *
- * Based on:
- * Author: Steve Sakoman <steve@sakoman.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/i2c/twl.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <plat/mcbsp.h>
-
-/* Register descriptions for twl4030 codec part */
-#include <linux/mfd/twl4030-audio.h>
-#include <linux/module.h>
-
-#include "omap-mcbsp.h"
-#include "omap-pcm.h"
-
-/* TWL4030 PMBR1 Register */
-#define TWL4030_INTBR_PMBR1 0x0D
-/* TWL4030 PMBR1 Register GPIO6 mux bit */
-#define TWL4030_GPIO6_PWM0_MUTE(value) (value << 2)
-
-static struct snd_soc_card snd_soc_sdp3430;
-
-static int sdp3430_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 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) {
- printk(KERN_ERR "can't set codec system clock\n");
- return ret;
- }
-
- return 0;
-}
-
-static struct snd_soc_ops sdp3430_ops = {
- .hw_params = sdp3430_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,
- },
-};
-
-/* Headset jack detection gpios */
-static struct snd_soc_jack_gpio hs_jack_gpios[] = {
- {
- .gpio = (OMAP_MAX_GPIO_LINES + 2),
- .name = "hsdet-gpio",
- .report = SND_JACK_HEADSET,
- .debounce_time = 200,
- },
-};
-
-/* SDP3430 machine DAPM */
-static const struct snd_soc_dapm_widget sdp3430_twl4030_dapm_widgets[] = {
- SND_SOC_DAPM_MIC("Ext Mic", NULL),
- SND_SOC_DAPM_SPK("Ext Spk", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_HP("Headset Stereophone", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
- /* External Mics: MAINMIC, SUBMIC with bias*/
- {"MAINMIC", NULL, "Mic Bias 1"},
- {"SUBMIC", NULL, "Mic Bias 2"},
- {"Mic Bias 1", NULL, "Ext Mic"},
- {"Mic Bias 2", NULL, "Ext Mic"},
-
- /* External Speakers: HFL, HFR */
- {"Ext Spk", NULL, "HFL"},
- {"Ext Spk", NULL, "HFR"},
-
- /* Headset Mic: HSMIC with bias */
- {"HSMIC", NULL, "Headset Mic Bias"},
- {"Headset Mic Bias", NULL, "Headset Mic"},
-
- /* Headset Stereophone (Headphone): HSOL, HSOR */
- {"Headset Stereophone", NULL, "HSOL"},
- {"Headset Stereophone", NULL, "HSOR"},
-};
-
-static int sdp3430_twl4030_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
-
- /* SDP3430 connected pins */
- snd_soc_dapm_enable_pin(dapm, "Ext Mic");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk");
- snd_soc_dapm_disable_pin(dapm, "Headset Mic");
- snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
-
- /* TWL4030 not connected pins */
- snd_soc_dapm_nc_pin(dapm, "AUXL");
- snd_soc_dapm_nc_pin(dapm, "AUXR");
- snd_soc_dapm_nc_pin(dapm, "CARKITMIC");
- snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
- snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
-
- snd_soc_dapm_nc_pin(dapm, "OUTL");
- snd_soc_dapm_nc_pin(dapm, "OUTR");
- 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, "CARKITL");
- snd_soc_dapm_nc_pin(dapm, "CARKITR");
-
- /* Headset jack detection */
- ret = snd_soc_jack_new(codec, "Headset Jack",
- SND_JACK_HEADSET, &hs_jack);
- if (ret)
- return ret;
-
- ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
- hs_jack_pins);
- if (ret)
- return ret;
-
- ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
- hs_jack_gpios);
-
- return ret;
-}
-
-static int sdp3430_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- unsigned short reg;
-
- /* Enable voice interface */
- reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF);
- reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
- codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg);
-
- return 0;
-}
-
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link sdp3430_dai[] = {
- {
- .name = "TWL4030 I2S",
- .stream_name = "TWL4030 Audio",
- .cpu_dai_name = "omap-mcbsp-dai.1",
- .codec_dai_name = "twl4030-hifi",
- .platform_name = "omap-pcm-audio",
- .codec_name = "twl4030-codec",
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
- .init = sdp3430_twl4030_init,
- .ops = &sdp3430_ops,
- },
- {
- .name = "TWL4030 PCM",
- .stream_name = "TWL4030 Voice",
- .cpu_dai_name = "omap-mcbsp-dai.2",
- .codec_dai_name = "twl4030-voice",
- .platform_name = "omap-pcm-audio",
- .codec_name = "twl4030-codec",
- .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
- .init = sdp3430_twl4030_voice_init,
- .ops = &sdp3430_ops,
- },
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_sdp3430 = {
- .name = "SDP3430",
- .owner = THIS_MODULE,
- .dai_link = sdp3430_dai,
- .num_links = ARRAY_SIZE(sdp3430_dai),
-
- .dapm_widgets = sdp3430_twl4030_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(sdp3430_twl4030_dapm_widgets),
- .dapm_routes = audio_map,
- .num_dapm_routes = ARRAY_SIZE(audio_map),
-};
-
-static struct platform_device *sdp3430_snd_device;
-
-static int __init sdp3430_soc_init(void)
-{
- int ret;
- u8 pin_mux;
-
- if (!machine_is_omap_3430sdp())
- return -ENODEV;
- printk(KERN_INFO "SDP3430 SoC init\n");
-
- sdp3430_snd_device = platform_device_alloc("soc-audio", -1);
- if (!sdp3430_snd_device) {
- printk(KERN_ERR "Platform device allocation failed\n");
- return -ENOMEM;
- }
-
- platform_set_drvdata(sdp3430_snd_device, &snd_soc_sdp3430);
-
- /* Set TWL4030 GPIO6 as EXTMUTE signal */
- twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux,
- TWL4030_INTBR_PMBR1);
- pin_mux &= ~TWL4030_GPIO6_PWM0_MUTE(0x03);
- pin_mux |= TWL4030_GPIO6_PWM0_MUTE(0x02);
- twl_i2c_write_u8(TWL4030_MODULE_INTBR, pin_mux,
- TWL4030_INTBR_PMBR1);
-
- ret = platform_device_add(sdp3430_snd_device);
- if (ret)
- goto err1;
-
- return 0;
-
-err1:
- printk(KERN_ERR "Unable to add platform device\n");
- platform_device_put(sdp3430_snd_device);
-
- return ret;
-}
-module_init(sdp3430_soc_init);
-
-static void __exit sdp3430_soc_exit(void)
-{
- snd_soc_jack_free_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
- hs_jack_gpios);
-
- platform_device_unregister(sdp3430_snd_device);
-}
-module_exit(sdp3430_soc_exit);
-
-MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
-MODULE_DESCRIPTION("ALSA SoC SDP3430");
-MODULE_LICENSE("GPL");
-
diff --git a/sound/soc/omap/sdp4430.c b/sound/soc/omap/sdp4430.c
deleted file mode 100644
index 175ba9a04ed..00000000000
--- a/sound/soc/omap/sdp4430.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * sdp4430.c -- SoC audio for TI OMAP4430 SDP
- *
- * Author: Misael Lopez Cruz <x0052729@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 <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-
-#include <asm/mach-types.h>
-#include <plat/hardware.h>
-#include <plat/mux.h>
-
-#include "omap-dmic.h"
-#include "omap-mcpdm.h"
-#include "omap-pcm.h"
-#include "../codecs/twl6040.h"
-
-static int sdp4430_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 clk_id, freq;
- int ret;
-
- clk_id = twl6040_get_clk_id(rtd->codec);
- if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
- freq = 38400000;
- 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 struct snd_soc_ops sdp4430_ops = {
- .hw_params = sdp4430_hw_params,
-};
-
-static int sdp4430_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 sdp4430_dmic_ops = {
- .hw_params = sdp4430_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 sdp4430_twl6040_dapm_widgets[] = {
- SND_SOC_DAPM_MIC("Ext Mic", NULL),
- SND_SOC_DAPM_SPK("Ext Spk", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_HP("Headset Stereophone", NULL),
- SND_SOC_DAPM_SPK("Earphone Spk", NULL),
- SND_SOC_DAPM_INPUT("FM Stereo In"),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
- /* External Mics: MAINMIC, SUBMIC with bias*/
- {"MAINMIC", NULL, "Main Mic Bias"},
- {"SUBMIC", NULL, "Main Mic Bias"},
- {"Main Mic Bias", NULL, "Ext Mic"},
-
- /* External Speakers: HFL, HFR */
- {"Ext Spk", NULL, "HFL"},
- {"Ext Spk", NULL, "HFR"},
-
- /* Headset Mic: HSMIC with bias */
- {"HSMIC", NULL, "Headset Mic Bias"},
- {"Headset Mic Bias", NULL, "Headset Mic"},
-
- /* Headset Stereophone (Headphone): HSOL, HSOR */
- {"Headset Stereophone", NULL, "HSOL"},
- {"Headset Stereophone", NULL, "HSOR"},
-
- /* Earphone speaker */
- {"Earphone Spk", NULL, "EP"},
-
- /* Aux/FM Stereo In: AFML, AFMR */
- {"AFML", NULL, "FM Stereo In"},
- {"AFMR", NULL, "FM Stereo In"},
-};
-
-static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- int ret, hs_trim;
-
- /*
- * Configure McPDM offset cancellation based on the HSOTRIM value from
- * twl6040.
- */
- hs_trim = twl6040_get_trim_value(codec, TWL6040_TRIM_HSOTRIM);
- omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim),
- TWL6040_HSF_TRIM_RIGHT(hs_trim));
-
- /* Headset jack detection */
- ret = snd_soc_jack_new(codec, "Headset Jack",
- SND_JACK_HEADSET, &hs_jack);
- if (ret)
- return ret;
-
- ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
- hs_jack_pins);
-
- if (machine_is_omap_4430sdp())
- twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
- else
- snd_soc_jack_report(&hs_jack, SND_JACK_HEADSET, SND_JACK_HEADSET);
-
- return ret;
-}
-
-static const struct snd_soc_dapm_widget sdp4430_dmic_dapm_widgets[] = {
- SND_SOC_DAPM_MIC("Digital Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route dmic_audio_map[] = {
- {"DMic", NULL, "Digital Mic1 Bias"},
- {"Digital Mic1 Bias", NULL, "Digital Mic"},
-};
-
-static int sdp4430_dmic_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
-
- ret = snd_soc_dapm_new_controls(dapm, sdp4430_dmic_dapm_widgets,
- ARRAY_SIZE(sdp4430_dmic_dapm_widgets));
- if (ret)
- return ret;
-
- return snd_soc_dapm_add_routes(dapm, dmic_audio_map,
- ARRAY_SIZE(dmic_audio_map));
-}
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link sdp4430_dai[] = {
- {
- .name = "TWL6040",
- .stream_name = "TWL6040",
- .cpu_dai_name = "omap-mcpdm",
- .codec_dai_name = "twl6040-legacy",
- .platform_name = "omap-pcm-audio",
- .codec_name = "twl6040-codec",
- .init = sdp4430_twl6040_init,
- .ops = &sdp4430_ops,
- },
- {
- .name = "DMIC",
- .stream_name = "DMIC Capture",
- .cpu_dai_name = "omap-dmic",
- .codec_dai_name = "dmic-hifi",
- .platform_name = "omap-pcm-audio",
- .codec_name = "dmic-codec",
- .init = sdp4430_dmic_init,
- .ops = &sdp4430_dmic_ops,
- },
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_sdp4430 = {
- .name = "SDP4430",
- .owner = THIS_MODULE,
- .dai_link = sdp4430_dai,
- .num_links = ARRAY_SIZE(sdp4430_dai),
-
- .dapm_widgets = sdp4430_twl6040_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(sdp4430_twl6040_dapm_widgets),
- .dapm_routes = audio_map,
- .num_dapm_routes = ARRAY_SIZE(audio_map),
-};
-
-static struct platform_device *sdp4430_snd_device;
-
-static int __init sdp4430_soc_init(void)
-{
- int ret;
-
- if (!machine_is_omap_4430sdp())
- return -ENODEV;
- printk(KERN_INFO "SDP4430 SoC init\n");
-
- sdp4430_snd_device = platform_device_alloc("soc-audio", -1);
- if (!sdp4430_snd_device) {
- printk(KERN_ERR "Platform device allocation failed\n");
- return -ENOMEM;
- }
-
- platform_set_drvdata(sdp4430_snd_device, &snd_soc_sdp4430);
-
- ret = platform_device_add(sdp4430_snd_device);
- if (ret)
- goto err;
-
- return 0;
-
-err:
- printk(KERN_ERR "Unable to add platform device\n");
- platform_device_put(sdp4430_snd_device);
- return ret;
-}
-module_init(sdp4430_soc_init);
-
-static void __exit sdp4430_soc_exit(void)
-{
- platform_device_unregister(sdp4430_snd_device);
-}
-module_exit(sdp4430_soc_exit);
-
-MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
-MODULE_DESCRIPTION("ALSA SoC SDP4430");
-MODULE_LICENSE("GPL");
-
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
deleted file mode 100644
index 981616d61f6..00000000000
--- a/sound/soc/omap/zoom2.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * zoom2.c -- SoC audio for Zoom2
- *
- * Author: Misael Lopez Cruz <x0052729@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 <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <mach/board-zoom.h>
-#include <plat/mcbsp.h>
-
-/* Register descriptions for twl4030 codec part */
-#include <linux/mfd/twl4030-audio.h>
-#include <linux/module.h>
-
-#include "omap-mcbsp.h"
-#include "omap-pcm.h"
-
-#define ZOOM2_HEADSET_MUX_GPIO (OMAP_MAX_GPIO_LINES + 15)
-
-static int zoom2_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 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) {
- printk(KERN_ERR "can't set codec system clock\n");
- return ret;
- }
-
- return 0;
-}
-
-static struct snd_soc_ops zoom2_ops = {
- .hw_params = zoom2_hw_params,
-};
-
-/* Zoom2 machine DAPM */
-static const struct snd_soc_dapm_widget zoom2_twl4030_dapm_widgets[] = {
- SND_SOC_DAPM_MIC("Ext Mic", NULL),
- SND_SOC_DAPM_SPK("Ext Spk", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_HP("Headset Stereophone", NULL),
- SND_SOC_DAPM_LINE("Aux In", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
- /* External Mics: MAINMIC, SUBMIC with bias*/
- {"MAINMIC", NULL, "Mic Bias 1"},
- {"SUBMIC", NULL, "Mic Bias 2"},
- {"Mic Bias 1", NULL, "Ext Mic"},
- {"Mic Bias 2", NULL, "Ext Mic"},
-
- /* External Speakers: HFL, HFR */
- {"Ext Spk", NULL, "HFL"},
- {"Ext Spk", NULL, "HFR"},
-
- /* Headset Stereophone: HSOL, HSOR */
- {"Headset Stereophone", NULL, "HSOL"},
- {"Headset Stereophone", NULL, "HSOR"},
-
- /* Headset Mic: HSMIC with bias */
- {"HSMIC", NULL, "Headset Mic Bias"},
- {"Headset Mic Bias", NULL, "Headset Mic"},
-
- /* Aux In: AUXL, AUXR */
- {"Aux In", NULL, "AUXL"},
- {"Aux In", NULL, "AUXR"},
-};
-
-static int zoom2_twl4030_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- /* TWL4030 not connected pins */
- snd_soc_dapm_nc_pin(dapm, "CARKITMIC");
- snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
- snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
- 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, "CARKITL");
- snd_soc_dapm_nc_pin(dapm, "CARKITR");
-
- return 0;
-}
-
-static int zoom2_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- unsigned short reg;
-
- /* Enable voice interface */
- reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF);
- reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
- codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg);
-
- return 0;
-}
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link zoom2_dai[] = {
- {
- .name = "TWL4030 I2S",
- .stream_name = "TWL4030 Audio",
- .cpu_dai_name = "omap-mcbsp-dai.1",
- .codec_dai_name = "twl4030-hifi",
- .platform_name = "omap-pcm-audio",
- .codec_name = "twl4030-codec",
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
- .init = zoom2_twl4030_init,
- .ops = &zoom2_ops,
- },
- {
- .name = "TWL4030 PCM",
- .stream_name = "TWL4030 Voice",
- .cpu_dai_name = "omap-mcbsp-dai.2",
- .codec_dai_name = "twl4030-voice",
- .platform_name = "omap-pcm-audio",
- .codec_name = "twl4030-codec",
- .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
- .init = zoom2_twl4030_voice_init,
- .ops = &zoom2_ops,
- },
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_zoom2 = {
- .name = "Zoom2",
- .owner = THIS_MODULE,
- .dai_link = zoom2_dai,
- .num_links = ARRAY_SIZE(zoom2_dai),
-
- .dapm_widgets = zoom2_twl4030_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(zoom2_twl4030_dapm_widgets),
- .dapm_routes = audio_map,
- .num_dapm_routes = ARRAY_SIZE(audio_map),
-};
-
-static struct platform_device *zoom2_snd_device;
-
-static int __init zoom2_soc_init(void)
-{
- int ret;
-
- if (!machine_is_omap_zoom2())
- return -ENODEV;
- printk(KERN_INFO "Zoom2 SoC init\n");
-
- zoom2_snd_device = platform_device_alloc("soc-audio", -1);
- if (!zoom2_snd_device) {
- printk(KERN_ERR "Platform device allocation failed\n");
- return -ENOMEM;
- }
-
- platform_set_drvdata(zoom2_snd_device, &snd_soc_zoom2);
- ret = platform_device_add(zoom2_snd_device);
- if (ret)
- goto err1;
-
- BUG_ON(gpio_request(ZOOM2_HEADSET_MUX_GPIO, "hs_mux") < 0);
- gpio_direction_output(ZOOM2_HEADSET_MUX_GPIO, 0);
-
- BUG_ON(gpio_request(ZOOM2_HEADSET_EXTMUTE_GPIO, "ext_mute") < 0);
- gpio_direction_output(ZOOM2_HEADSET_EXTMUTE_GPIO, 0);
-
- return 0;
-
-err1:
- printk(KERN_ERR "Unable to add platform device\n");
- platform_device_put(zoom2_snd_device);
-
- return ret;
-}
-module_init(zoom2_soc_init);
-
-static void __exit zoom2_soc_exit(void)
-{
- gpio_free(ZOOM2_HEADSET_MUX_GPIO);
- gpio_free(ZOOM2_HEADSET_EXTMUTE_GPIO);
-
- platform_device_unregister(zoom2_snd_device);
-}
-module_exit(zoom2_soc_exit);
-
-MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
-MODULE_DESCRIPTION("ALSA SoC Zoom2");
-MODULE_LICENSE("GPL");
-