diff options
28 files changed, 1164 insertions, 601 deletions
diff --git a/arch/arm/configs/herring_defconfig b/arch/arm/configs/herring_defconfig index 476f8ee..37d615c 100755 --- a/arch/arm/configs/herring_defconfig +++ b/arch/arm/configs/herring_defconfig @@ -222,8 +222,8 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_SOC=y -CONFIG_SND_S3C24XX_SOC=y -CONFIG_SND_S5P_WM8994=y +CONFIG_SND_SOC_SAMSUNG=y +CONFIG_SND_SOC_SAMSUNG_HERRING_WM8994=y # CONFIG_HID_SUPPORT is not set CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=500 diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c index ae3aa2f..6d3e609 100644 --- a/arch/arm/mach-s5pv210/clock.c +++ b/arch/arm/mach-s5pv210/clock.c @@ -534,6 +534,7 @@ static struct clk init_clocks_off[] = { .enable = s5pv210_clk_ip3_ctrl, .ctrlbit = S5P_CLKGATE_IP3_PCM2, }, { +#if 0 .name = "pcm", .id = 1, .parent = &clk_pclk_psys.clk, @@ -546,6 +547,7 @@ static struct clk init_clocks_off[] = { .enable = s5pv210_clk_ip3_ctrl, .ctrlbit = S5P_CLKGATE_IP3_PCM0, }, { +#endif .name = "i2c-hdmiphy", .id = -1, .parent = &clk_pclk_psys.clk, @@ -679,12 +681,14 @@ static struct clk init_clocks[] = { .enable = s5pv210_clk_ip1_ctrl, .ctrlbit = (1 << 26), }, { +#if 1 .name = "i2s_v50", .id = 0, .parent = &clk_p, .enable = s5pv210_clk_ip3_ctrl, .ctrlbit = S5P_CLKGATE_IP3_I2S0 | S5P_CLKGATE_IP3_PCM0, }, { +#endif .name = "clk_out", .id = -1, .ops = &s5pc11x_clkout_ops, diff --git a/arch/arm/mach-s5pv210/dev-audio.c b/arch/arm/mach-s5pv210/dev-audio.c index 0959bfe..c6109b1 100644 --- a/arch/arm/mach-s5pv210/dev-audio.c +++ b/arch/arm/mach-s5pv210/dev-audio.c @@ -80,7 +80,7 @@ static struct resource s5pv210_iis0_resource[] = { }; struct platform_device s5pv210_device_iis0 = { - .name = "s5pc1xx-iis", + .name = "samsung-i2s", .id = 0, .num_resources = ARRAY_SIZE(s5pv210_iis0_resource), .resource = s5pv210_iis0_resource, diff --git a/arch/arm/mach-s5pv210/mach-herring.c b/arch/arm/mach-s5pv210/mach-herring.c index d54a949..f59484d 100755 --- a/arch/arm/mach-s5pv210/mach-herring.c +++ b/arch/arm/mach-s5pv210/mach-herring.c @@ -2731,7 +2731,7 @@ static struct i2c_board_info i2c_devs0[] __initdata = { static struct i2c_board_info i2c_devs4[] __initdata = { { - I2C_BOARD_INFO("wm8994", (0x34>>1)), + I2C_BOARD_INFO("wm8994-samsung", (0x34>>1)), .platform_data = &wm8994_pdata, }, }; @@ -5473,6 +5473,7 @@ static struct platform_device *herring_devices[] __initdata = { &sec_device_btsleep, &ram_console_device, &sec_device_wifi, + &samsung_asoc_dma, }; unsigned int HWREV; diff --git a/arch/arm/mach-s5pv210/power-domain.c b/arch/arm/mach-s5pv210/power-domain.c index 0a10ef2..3383878 100644 --- a/arch/arm/mach-s5pv210/power-domain.c +++ b/arch/arm/mach-s5pv210/power-domain.c @@ -40,7 +40,7 @@ struct clk_should_be_running { }; static struct regulator_consumer_supply s5pv210_pd_audio_supply[] = { - REGULATOR_SUPPLY("pd", "s5pc1xx-iis.0"), + REGULATOR_SUPPLY("pd", "samsung-i2s.0"), }; static struct regulator_consumer_supply s5pv210_pd_cam_supply[] = { diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 98175a0..abfd23b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -356,6 +356,9 @@ config SND_SOC_WM8993 config SND_SOC_WM8994 tristate +config SND_SOC_WM8994_SAMSUNG + tristate + config SND_SOC_WM8995 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index fd85584..98bc006 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -74,6 +74,7 @@ snd-soc-wm8990-objs := wm8990.o snd-soc-wm8991-objs := wm8991.o snd-soc-wm8993-objs := wm8993.o snd-soc-wm8994-objs := wm8994.o wm8994-tables.o wm8958-dsp2.o +snd-soc-wm8994-samsung-objs := wm8994_samsung.o wm8994_herring.o snd-soc-wm8995-objs := wm8995.o snd-soc-wm9081-objs := wm9081.o snd-soc-wm9705-objs := wm9705.o @@ -166,6 +167,7 @@ obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o obj-$(CONFIG_SND_SOC_WM8991) += snd-soc-wm8991.o obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o obj-$(CONFIG_SND_SOC_WM8994) += snd-soc-wm8994.o +obj-$(CONFIG_SND_SOC_WM8994_SAMSUNG) += snd-soc-wm8994-samsung.o obj-$(CONFIG_SND_SOC_WM8995) += snd-soc-wm8995.o obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 0a1db04..13257dc 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -1,145 +1,120 @@ -/* - * wm8994.h -- WM8994 Soc Audio driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _WM8994_H -#define _WM8994_H - -#include <sound/soc.h> -#include <linux/firmware.h> - -#include "wm_hubs.h" - -/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */ -#define WM8994_SYSCLK_MCLK1 1 -#define WM8994_SYSCLK_MCLK2 2 -#define WM8994_SYSCLK_FLL1 3 -#define WM8994_SYSCLK_FLL2 4 - -/* OPCLK is also configured with set_dai_sysclk, specify division*10 as rate. */ -#define WM8994_SYSCLK_OPCLK 5 - -#define WM8994_FLL1 1 -#define WM8994_FLL2 2 - -#define WM8994_FLL_SRC_MCLK1 1 -#define WM8994_FLL_SRC_MCLK2 2 -#define WM8994_FLL_SRC_LRCLK 3 -#define WM8994_FLL_SRC_BCLK 4 - -typedef void (*wm8958_micdet_cb)(u16 status, void *data); - -int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, - int micbias, int det, int shrt); -int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, - wm8958_micdet_cb cb, void *cb_data); - -#define WM8994_CACHE_SIZE 1570 - -struct wm8994_access_mask { - unsigned short readable; /* Mask of readable bits */ - unsigned short writable; /* Mask of writable bits */ -}; - -extern const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE]; -extern const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE]; - -int wm8958_aif_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event); - -void wm8958_dsp2_init(struct snd_soc_codec *codec); - -struct wm8994_micdet { - struct snd_soc_jack *jack; - int det; - int shrt; -}; - -/* codec private data */ -struct wm8994_fll_config { - int src; - int in; - int out; -}; - -#define WM8994_NUM_DRC 3 -#define WM8994_NUM_EQ 3 - -struct wm8994_priv { - struct wm_hubs_data hubs; - enum snd_soc_control_type control_type; - void *control_data; - struct snd_soc_codec *codec; - int sysclk[2]; - int sysclk_rate[2]; - int mclk[2]; - int aifclk[2]; - struct wm8994_fll_config fll[2], fll_suspend[2]; - - int dac_rates[2]; - int lrclk_shared[2]; - - int mbc_ena[3]; - int hpf1_ena[3]; - int hpf2_ena[3]; - int vss_ena[3]; - int enh_eq_ena[3]; - - /* Platform dependant DRC configuration */ - const char **drc_texts; - int drc_cfg[WM8994_NUM_DRC]; - struct soc_enum drc_enum; - - /* Platform dependant ReTune mobile configuration */ - int num_retune_mobile_texts; - const char **retune_mobile_texts; - int retune_mobile_cfg[WM8994_NUM_EQ]; - struct soc_enum retune_mobile_enum; - - /* Platform dependant MBC configuration */ - int mbc_cfg; - const char **mbc_texts; - struct soc_enum mbc_enum; - - /* Platform dependant VSS configuration */ - int vss_cfg; - const char **vss_texts; - struct soc_enum vss_enum; - - /* Platform dependant VSS HPF configuration */ - int vss_hpf_cfg; - const char **vss_hpf_texts; - struct soc_enum vss_hpf_enum; - - /* Platform dependant enhanced EQ configuration */ - int enh_eq_cfg; - const char **enh_eq_texts; - struct soc_enum enh_eq_enum; - - struct wm8994_micdet micdet[2]; - - wm8958_micdet_cb jack_cb; - void *jack_cb_data; - int micdet_irq; - - int revision; - struct wm8994_pdata *pdata; - - unsigned int aif1clk_enable:1; - unsigned int aif2clk_enable:1; - - unsigned int aif1clk_disable:1; - unsigned int aif2clk_disable:1; - - int dsp_active; - const struct firmware *cur_fw; - const struct firmware *mbc; - const struct firmware *mbc_vss; - const struct firmware *enh_eq; -}; - -#endif +/*
+ * wm8994.h -- WM8994 Soc Audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8994_H
+#define _WM8994_H
+
+#include <sound/soc.h>
+
+extern struct snd_soc_codec_device soc_codec_dev_wm8994;
+// We don't use array - DW Shim.
+//extern struct snd_soc_dai wm8994_dai[];
+
+/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
+#define WM8994_SYSCLK_MCLK1 1
+#define WM8994_SYSCLK_MCLK2 2
+#define WM8994_SYSCLK_FLL1 3
+#define WM8994_SYSCLK_FLL2 4
+
+#define WM8994_FLL1 1
+#define WM8994_FLL2 2
+
+//-----------------------------------------------------------
+// Added belows codes by Samsung Electronics.
+
+#include "wm8994_def.h"
+
+extern struct snd_soc_dai wm8994_dai;
+
+#define WM8994_SYSCLK_MCLK 1
+#define WM8994_SYSCLK_FLL 2
+
+#define AUDIO_COMMON_DEBUG 0
+//#define WM8994_REGISTER_DUMP
+#if defined CONFIG_SND_SOC_WM8994_PCM
+#define ATTACH_ADDITINAL_PCM_DRIVER // for VT call.
+#endif
+//------------------------------------------------
+// Definitions of enum type
+//------------------------------------------------
+enum audio_path { OFF, RCV, SPK, HP, BT, SPK_HP};
+enum mic_path { MAIN, SUB, MIC_OFF};
+enum fmradio_audio_path { FMR_OFF, FMR_SPK, FMR_HP, FMR_SPK_MIX, FMR_HP_MIX, FMR_SPK_HP_MIX};
+enum call_state { DISCONNECT, CONNECT};
+enum power_state { CODEC_OFF, CODEC_ON };
+enum mic_state { MIC_NO_USE, MIC_USE};
+
+typedef void (*select_route)(struct snd_soc_codec *);
+typedef void (*select_mic_route)(struct snd_soc_codec *);
+
+struct wm8994_setup_data {
+ int i2c_bus;
+ unsigned short i2c_address;
+};
+
+struct wm8994_priv {
+ //u16 reg_cache[WM8994_REGISTER_COUNT];
+ struct snd_soc_codec codec;
+ int master;
+ int sysclk_source;
+ unsigned int mclk_rate;
+ unsigned int sysclk_rate;
+ unsigned int fs;
+ unsigned int bclk;
+ unsigned int hw_version; // For wolfson H/W version. 1 = Rev B, 3 = Rev D
+ enum audio_path cur_path;
+ enum mic_path rec_path;
+ enum fmradio_audio_path fmradio_path;
+ enum call_state call_state;
+ enum power_state power_state;
+ enum mic_state mic_state;
+ select_route *universal_playback_path;
+ select_route *universal_voicecall_path;
+ select_mic_route *universal_mic_path;
+ int testmode_config_flag; // for testmode.
+};
+
+#if AUDIO_COMMON_DEBUG
+#define DEBUG_LOG(format,...)\
+ printk ("[ "SUBJECT " (%s,%d) ] " format "\n", __func__, __LINE__, ## __VA_ARGS__);
+#else
+#define DEBUG_LOG(format,...)
+#endif
+
+#define DEBUG_LOG_ERR(format,...)\
+ printk (KERN_ERR "[ "SUBJECT " (%s,%d) ] " format "\n", __func__, __LINE__, ## __VA_ARGS__);
+
+// Definitions of function prototype.
+inline unsigned int wm8994_read(struct snd_soc_codec *codec,unsigned int reg);
+int wm8994_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value);
+int audio_init(void);
+int audio_power(int en);
+void audio_ctrl_mic_bias_gpio(int enable);
+void wm8994_set_off(struct snd_soc_codec *codec);
+void wm8994_disable_playback_path(struct snd_soc_codec *codec, enum audio_path path);
+void wm8994_disable_fmradio_path(struct snd_soc_codec *codec, enum fmradio_audio_path path);
+void wm8994_disable_rec_path(struct snd_soc_codec *codec,enum mic_path rec_path);
+void wm8994_record_main_mic( struct snd_soc_codec *codec);
+void wm8994_record_headset_mic( struct snd_soc_codec *codec);
+void wm8994_set_playback_receiver(struct snd_soc_codec *codec);
+void wm8994_set_playback_headset(struct snd_soc_codec *codec);
+void wm8994_set_playback_speaker(struct snd_soc_codec *codec);
+void wm8994_set_playback_speaker_headset(struct snd_soc_codec *codec);
+void wm8994_set_voicecall_receiver(struct snd_soc_codec *codec);
+void wm8994_set_voicecall_headset(struct snd_soc_codec *codec);
+void wm8994_set_voicecall_speaker(struct snd_soc_codec *codec);
+void wm8994_set_voicecall_bluetooth(struct snd_soc_codec *codec);
+void wm8994_set_fmradio_headset(struct snd_soc_codec *codec);
+void wm8994_set_fmradio_speaker(struct snd_soc_codec *codec);
+void wm8994_set_fmradio_headset_mix(struct snd_soc_codec *codec);
+void wm8994_set_fmradio_speaker_mix(struct snd_soc_codec *codec);
+void wm8994_set_fmradio_speaker_headset_mix(struct snd_soc_codec *codec);
+#if defined WM8994_REGISTER_DUMP
+void wm8994_register_dump(struct snd_soc_codec *codec);
+#endif
+#endif
diff --git a/sound/soc/codecs/wm8994_def.h b/sound/soc/codecs/wm8994_def.h index 957d3f7..a375950 100644 --- a/sound/soc/codecs/wm8994_def.h +++ b/sound/soc/codecs/wm8994_def.h @@ -69,6 +69,10 @@ #define WM8994_DC_SERVO_ANA_1 0x5B
#define WM8994_DC_SERVO_ANA_2 0x5C
#define WM8994_ANALOGUE_HP_1 0x60
+#define WM8958_MIC_DETECT_1 0xD0 +#define WM8958_MIC_DETECT_2 0xD1 +#define WM8958_MIC_DETECT_3 0xD2 +#define WM8994_CHIP_REVISION 0x100 #define WM8994_CONTROL_INTERFACE 0x101
#define WM8994_WRITE_SEQUENCER_CTRL_1 0x110
#define WM8994_WRITE_SEQUENCER_CTRL_2 0x111
@@ -239,6 +243,7 @@ #define WM8994_INTERRUPT_CONTROL 0x740
#define WM8994_IRQ_DEBOUNCE 0x748
#define WM8994_IRQ_POLARITY 0x749
+#define WM8958_DSP2_EXECCONTROL 0xA0D #define WM8994_WRITE_SEQUENCER_0 0x3000
#define WM8994_WRITE_SEQUENCER_1 0x3001
#define WM8994_WRITE_SEQUENCER_2 0x3002
diff --git a/sound/soc/codecs/wm8994_herring.c b/sound/soc/codecs/wm8994_herring.c index bb67f85..6db5065 100755 --- a/sound/soc/codecs/wm8994_herring.c +++ b/sound/soc/codecs/wm8994_herring.c @@ -1121,7 +1121,7 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op) /* S5P_SLEEP_CONFIG must be controlled by codec if codec use XUSBTI */ int wm8994_configure_clock(struct snd_soc_codec *codec, int en) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); if (en) { clk_enable(wm8994->codec_clk); @@ -1165,7 +1165,7 @@ static int wm8994_earsel_control(struct wm8994_platform_data *pdata, int en) /* Audio Routing routines for the universal board..wm8994 codec*/ void wm8994_disable_path(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); u16 val; enum audio_path path = wm8994->cur_path; @@ -1330,7 +1330,7 @@ void wm8994_disable_path(struct snd_soc_codec *codec) void wm8994_disable_rec_path(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); u16 val; enum mic_path mic = wm8994->rec_path; @@ -1514,7 +1514,7 @@ void wm8994_set_bluetooth_common_setting(struct snd_soc_codec *codec) void wm8994_record_headset_mic(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); u16 val; @@ -1627,7 +1627,7 @@ void wm8994_record_headset_mic(struct snd_soc_codec *codec) void wm8994_record_main_mic(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); u16 val; @@ -1894,7 +1894,7 @@ void wm8994_set_playback_receiver(struct snd_soc_codec *codec) void wm8994_set_playback_headset(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); u16 val; @@ -2077,7 +2077,7 @@ void wm8994_set_playback_headset(struct snd_soc_codec *codec) void wm8994_set_playback_speaker(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); u16 val; @@ -2185,7 +2185,7 @@ void wm8994_set_playback_speaker(struct snd_soc_codec *codec) void wm8994_set_playback_speaker_headset(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); u16 val; @@ -2595,7 +2595,7 @@ void wm8994_set_voicecall_common_setting(struct snd_soc_codec *codec) static void wm8994_set_cdma_voicecall_receiver(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int val; @@ -2716,7 +2716,7 @@ static void wm8994_set_cdma_voicecall_receiver(struct snd_soc_codec *codec) static void wm8994_set_gsm_voicecall_receiver(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int val; @@ -2818,7 +2818,7 @@ void wm8994_set_voicecall_receiver(struct snd_soc_codec *codec) void wm8994_set_voicecall_headset(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int val; @@ -2983,7 +2983,7 @@ void wm8994_set_voicecall_headset(struct snd_soc_codec *codec) void wm8994_set_voicecall_headphone(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int val; @@ -3140,7 +3140,7 @@ void wm8994_set_voicecall_headphone(struct snd_soc_codec *codec) void wm8994_set_voicecall_speaker(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int val; @@ -3305,7 +3305,7 @@ void wm8994_set_voicecall_bluetooth(struct snd_soc_codec *codec) void wm8994_set_voicecall_tty_vco(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int val; @@ -3462,7 +3462,7 @@ void wm8994_set_voicecall_tty_vco(struct snd_soc_codec *codec) void wm8994_set_voicecall_tty_hco(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int val; @@ -3632,7 +3632,7 @@ void wm8994_set_voicecall_tty_hco(struct snd_soc_codec *codec) void wm8994_set_voicecall_tty_full(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int val; @@ -3792,7 +3792,7 @@ void wm8994_set_voicecall_tty_full(struct snd_soc_codec *codec) int wm8994_set_codec_gain(struct snd_soc_codec *codec, u16 mode, u16 device) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int i; u32 gain_set_bits = COMMON_SET_BIT; u16 val; diff --git a/sound/soc/codecs/wm8994_samsung.c b/sound/soc/codecs/wm8994_samsung.c index 0fecae5..a9e569b 100755 --- a/sound/soc/codecs/wm8994_samsung.c +++ b/sound/soc/codecs/wm8994_samsung.c @@ -48,6 +48,8 @@ #define HDMI_USE_AUDIO #endif +//extern const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE]; + /* *Definitions of clock related. */ @@ -101,14 +103,14 @@ static struct { { 48, 9 }, }; -struct snd_soc_dai wm8994_dai; -EXPORT_SYMBOL_GPL(wm8994_dai); +//struct snd_soc_dai wm8994_dai; +//EXPORT_SYMBOL_GPL(wm8994_dai); -struct snd_soc_codec_device soc_codec_dev_pcm_wm8994; -EXPORT_SYMBOL_GPL(soc_codec_dev_pcm_wm8994); +//struct snd_soc_codec_device soc_codec_dev_pcm_wm8994; +//EXPORT_SYMBOL_GPL(soc_codec_dev_pcm_wm8994); -struct snd_soc_codec_device soc_codec_dev_wm8994; -EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994); +//struct snd_soc_codec_device soc_codec_dev_wm8994; +//EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994); /* * Definitions of sound path @@ -231,7 +233,7 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; int reg = mc->reg; - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); DEBUG_LOG(""); @@ -292,7 +294,7 @@ static int wm8994_get_mic_path(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = wm8994->rec_path; @@ -303,7 +305,7 @@ static int wm8994_set_mic_path(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); DEBUG_LOG(""); @@ -335,7 +337,7 @@ static int wm8994_get_path(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = wm8994->cur_path; @@ -346,7 +348,7 @@ static int wm8994_set_path(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct soc_enum *mc = (struct soc_enum *)kcontrol->private_value; int val; int path_num = ucontrol->value.integer.value[0]; @@ -412,7 +414,7 @@ static int wm8994_get_voice_path(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); ucontrol->value.integer.value[0] = wm8994->cur_path; @@ -423,7 +425,7 @@ static int wm8994_set_voice_path(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct soc_enum *mc = (struct soc_enum *)kcontrol->private_value; int path_num = ucontrol->value.integer.value[0]; @@ -473,7 +475,7 @@ static int wm8994_get_input_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); DEBUG_LOG("input_source_state = [%d]", wm8994->input_source); @@ -484,7 +486,7 @@ static int wm8994_set_input_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int control_flag = ucontrol->value.integer.value[0]; @@ -569,16 +571,8 @@ static const struct snd_kcontrol_new wm8994_snd_controls[] = { /* Add non-DAPM controls */ static int wm8994_add_controls(struct snd_soc_codec *codec) { - int err, i; - - for (i = 0; i < ARRAY_SIZE(wm8994_snd_controls); i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&wm8994_snd_controls[i], - codec, NULL)); - if (err < 0) - return err; - } - return 0; + return snd_soc_add_controls(codec, wm8994_snd_controls, + ARRAY_SIZE(wm8994_snd_controls)); } static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { }; @@ -588,18 +582,18 @@ static const struct snd_soc_dapm_route audio_map[] = { static int wm8994_add_widgets(struct snd_soc_codec *codec) { - snd_soc_dapm_new_controls(codec, wm8994_dapm_widgets, + snd_soc_dapm_new_controls(&codec->dapm, wm8994_dapm_widgets, ARRAY_SIZE(wm8994_dapm_widgets)); - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + snd_soc_dapm_add_routes(&codec->dapm, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); + snd_soc_dapm_new_widgets(&codec->dapm); return 0; } static int configure_clock(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); unsigned int reg; DEBUG_LOG(""); @@ -770,7 +764,7 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, break; case SND_SOC_BIAS_STANDBY: - if (codec->bias_level == SND_SOC_BIAS_OFF) { + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { /* Bring up VMID with fast soft start */ snd_soc_update_bits(codec, WM8994_ANTIPOP_2, WM8994_STARTUP_BIAS_ENA | @@ -810,7 +804,7 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, break; } - codec->bias_level = level; + codec->dapm.bias_level = level; return 0; } @@ -819,7 +813,7 @@ static int wm8994_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); DEBUG_LOG("clk_id =%d ", clk_id); @@ -843,7 +837,7 @@ static int wm8994_set_sysclk(struct snd_soc_dai *codec_dai, static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_codec *codec = dai->codec; - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); unsigned int aif1 = wm8994_read(codec, WM8994_AIF1_CONTROL_1); unsigned int aif2 = wm8994_read(codec, WM8994_AIF1_MASTER_SLAVE); @@ -945,7 +939,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int ret, i, best, best_val, cur_val; unsigned int clocking1, clocking3, aif1, aif4, aif5; @@ -1105,7 +1099,7 @@ static int wm8994_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai) { struct snd_soc_codec *codec = codec_dai->codec; - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) wm8994->stream_state |= PCM_STREAM_PLAYBACK; @@ -1135,7 +1129,7 @@ static void wm8994_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai) { struct snd_soc_codec *codec = codec_dai->codec; - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); DEBUG_LOG("Stream_state = [0x%X], Codec State = [0x%X]", wm8994->stream_state, wm8994->codec_state); @@ -1179,7 +1173,7 @@ static void wm8994_shutdown(struct snd_pcm_substream *substream, } } -static struct snd_soc_device *wm8994_socdev; +//static struct snd_soc_device *wm8994_socdev; static struct snd_soc_codec *wm8994_codec; #define WM8994_RATES SNDRV_PCM_RATE_44100 @@ -1194,25 +1188,25 @@ static struct snd_soc_dai_ops wm8994_ops = { .digital_mute = NULL, }; -struct snd_soc_dai wm8994_dai = { - - .name = "WM8994 PAIFRX", - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 6, - .rates = WM8994_RATES, - .formats = WM8994_FORMATS, - }, - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = WM8994_RATES, - .formats = WM8994_FORMATS, - }, - - .ops = &wm8994_ops, +struct snd_soc_dai_driver wm8994_dai[] = { + { + .name = "WM8994 PAIFRX", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 6, + .rates = WM8994_RATES, + .formats = WM8994_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = WM8994_RATES, + .formats = WM8994_FORMATS, + }, + .ops = &wm8994_ops, + }, }; /* gain_code range : integer 0~3 */ @@ -2827,7 +2821,7 @@ static const struct { { 0x03C3, 0x03C3 }, /* R1569 - Sidetone */ }; -static int wm8994_readable_register(unsigned int reg) +static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg) { switch (reg) { case WM8994_GPIO_1: @@ -2853,6 +2847,27 @@ static int wm8994_readable_register(unsigned int reg) return access_masks[reg].readable != 0; } +static int wm8994_volatile(struct snd_soc_codec *codec, unsigned int reg) +{ + //if (reg >= WM8994_CACHE_SIZE) + // return 1; + + switch (reg) { + case WM8994_SOFTWARE_RESET: + case WM8994_CHIP_REVISION: + case WM8994_DC_SERVO_1: + case WM8994_DC_SERVO_READBACK: + case WM8994_RATE_STATUS: + case WM8994_LDO_1: + case WM8994_LDO_2: + case WM8958_DSP2_EXECCONTROL: + case WM8958_MIC_DETECT_3: + return 1; + default: + return 0; + } +} + /* * initialise the WM8994 driver * register the mixer and dsp interfaces with the kernel @@ -2860,16 +2875,17 @@ static int wm8994_readable_register(unsigned int reg) static int wm8994_init(struct wm8994_priv *wm8994_private, struct wm8994_platform_data *pdata) { - struct snd_soc_codec *codec = &wm8994_private->codec; + struct snd_soc_codec *codec = wm8994_private->codec; struct wm8994_priv *wm8994; int ret = 0; DEBUG_LOG(""); - codec->drvdata = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL); - if (codec->drvdata == NULL) + wm8994 = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL); + if (wm8994 == NULL) return -ENOMEM; - wm8994 = codec->drvdata; + snd_soc_codec_set_drvdata(codec, wm8994); +#if 0 mutex_init(&codec->mutex); INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); @@ -2882,6 +2898,7 @@ static int wm8994_init(struct wm8994_priv *wm8994_private, codec->set_bias_level = NULL; codec->dai = &wm8994_dai; codec->num_dai = 1; +#endif wm8994->universal_playback_path = universal_wm8994_playback_paths; wm8994->universal_voicecall_path = universal_wm8994_voicecall_paths; wm8994->universal_mic_path = universal_wm8994_mic_paths; @@ -2910,15 +2927,17 @@ static int wm8994_init(struct wm8994_priv *wm8994_private, wm8994->hw_version = wm8994_read(codec, 0x100); - wm8994_socdev->card->codec = codec; + //wm8994_socdev->card->codec = codec; wm8994_codec = codec; +#if 0 ret = snd_soc_new_pcms(wm8994_socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { DEBUG_LOG_ERR("failed to create pcms\n"); goto pcm_err; } +#endif wm8994_add_controls(codec); wm8994_add_widgets(codec); @@ -2926,8 +2945,8 @@ static int wm8994_init(struct wm8994_priv *wm8994_private, return ret; card_err: - snd_soc_free_pcms(wm8994_socdev); - snd_soc_dapm_free(wm8994_socdev); + //snd_soc_free_pcms(wm8994_socdev); + //snd_soc_dapm_free(wm8994_socdev); pcm_err: return ret; @@ -2936,39 +2955,33 @@ pcm_err: /* If the i2c layer weren't so broken, we could pass this kind of data around */ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - - -static void *control_data1; - -static int wm8994_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8994_codec_probe(struct snd_soc_codec *codec) { - struct snd_soc_codec *codec; struct wm8994_priv *wm8994_priv; int ret = -ENODEV; struct wm8994_platform_data *pdata; DEBUG_LOG(""); + pr_info("WM8994 Audio Codec %s\n", WM8994_VERSION); wm8994_priv = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL); if (wm8994_priv == NULL) return -ENOMEM; - codec = &wm8994_priv->codec; + wm8994_priv->codec = codec; #ifdef PM_DEBUG pm_codec = codec; #endif - pdata = i2c->dev.platform_data; + pdata = dev_get_platdata(codec->dev); if (!pdata) { - dev_err(&i2c->dev, "failed to initialize WM8994\n"); + dev_err(codec->dev, "failed to initialize WM8994\n"); goto err_bad_pdata; } if (!pdata->set_mic_bias) { - dev_err(&i2c->dev, "bad pdata WM8994\n"); + dev_err(codec->dev, "bad pdata WM8994\n"); goto err_bad_pdata; } @@ -3005,14 +3018,14 @@ static int wm8994_i2c_probe(struct i2c_client *i2c, wm8994_ldo_control(pdata, 1); codec->hw_write = (hw_write_t) i2c_master_send; - i2c_set_clientdata(i2c, wm8994_priv); - codec->control_data = i2c; - codec->dev = &i2c->dev; - control_data1 = i2c; + //i2c_set_clientdata(i2c, wm8994_priv); + //codec->control_data = i2c; + codec->control_data = to_i2c_client(codec->dev); + //codec->dev = &i2c->dev; ret = wm8994_init(wm8994_priv, pdata); if (ret) { - dev_err(&i2c->dev, "failed to initialize WM8994\n"); + dev_err(codec->dev, "failed to initialize WM8994\n"); goto err_init; } @@ -3028,9 +3041,9 @@ err_bad_pdata: return ret; } -static int wm8994_i2c_remove(struct i2c_client *client) +static int wm8994_codec_remove(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994_priv = i2c_get_clientdata(client); + struct wm8994_priv *wm8994_priv = snd_soc_codec_get_drvdata(codec); gpio_free(wm8994_priv->pdata->ldo); gpio_free(wm8994_priv->pdata->ear_sel); @@ -3039,86 +3052,31 @@ static int wm8994_i2c_remove(struct i2c_client *client) return 0; } -static const struct i2c_device_id wm8994_i2c_id[] = { - {"wm8994", 0}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); - -static struct i2c_driver wm8994_i2c_driver = { - .driver = { - .name = "WM8994 I2C Codec", - .owner = THIS_MODULE, - }, - .probe = wm8994_i2c_probe, - .remove = wm8994_i2c_remove, - .id_table = wm8994_i2c_id, -}; - -static int wm8994_add_i2c_device(struct platform_device *pdev, - const struct wm8994_setup_data *setup) -{ - int ret; - - ret = i2c_add_driver(&wm8994_i2c_driver); - if (ret != 0) { - dev_err(&pdev->dev, "can't add i2c driver\n"); - return ret; - } - - return 0; - -err_driver: - i2c_del_driver(&wm8994_i2c_driver); - return -ENODEV; -} -#endif - -static int wm8994_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct wm8994_setup_data *setup; - - int ret = 0; - - pr_info("WM8994 Audio Codec %s\n", WM8994_VERSION); - - setup = socdev->codec_data; - wm8994_socdev = socdev; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - if (setup->i2c_address) - ret = wm8994_add_i2c_device(pdev, setup); -#else - /* Add other interfaces here */ -#endif - return ret; -} - +#if 0 /* power down chip */ static int wm8994_remove(struct platform_device *pdev) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); + //struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = wm8994_codec; - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); + //snd_soc_free_pcms(socdev); + //snd_soc_dapm_free(socdev); #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) i2c_unregister_device(codec->control_data); i2c_del_driver(&wm8994_i2c_driver); #endif - kfree(codec->drvdata); + //kfree(codec->drvdata); return 0; } +#endif #ifdef CONFIG_PM -static int wm8994_suspend(struct platform_device *pdev, pm_message_t msg) +static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state) { - struct snd_soc_codec *codec = wm8994_codec; - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); DEBUG_LOG("Codec State = [0x%X], Stream State = [0x%X]", wm8994->codec_state, wm8994->stream_state); @@ -3134,10 +3092,9 @@ static int wm8994_suspend(struct platform_device *pdev, pm_message_t msg) return 0; } -static int wm8994_resume(struct platform_device *pdev) +static int wm8994_resume(struct snd_soc_codec *codec) { - struct snd_soc_codec *codec = wm8994_codec; - struct wm8994_priv *wm8994 = codec->drvdata; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); DEBUG_LOG("%s..", __func__); DEBUG_LOG_ERR("------WM8994 Revision = [%d]-------", @@ -3152,6 +3109,7 @@ static int wm8994_resume(struct platform_device *pdev) } #endif +#if 0 struct snd_soc_codec_device soc_codec_dev_wm8994 = { .probe = wm8994_probe, .remove = wm8994_remove, @@ -3160,7 +3118,9 @@ struct snd_soc_codec_device soc_codec_dev_wm8994 = { .resume = wm8994_resume, #endif }; +#endif +#if 0 static int __init wm8994_modinit(void) { int ret; @@ -3179,6 +3139,68 @@ static void __exit wm8994_exit(void) } module_exit(wm8994_exit); +#endif + +static struct snd_soc_codec_driver soc_codec_dev_wm8994 = { + .probe = wm8994_codec_probe, + .remove = wm8994_codec_remove, + .suspend = wm8994_suspend, + .resume = wm8994_resume, + .read = wm8994_read, + .write = wm8994_write, + .readable_register = wm8994_readable, + .volatile_register = wm8994_volatile, + //.set_bias_level = wm8994_set_bias_level, + + .reg_cache_size = WM8994_IRQ_POLARITY, + //.reg_cache_size = WM8994_CACHE_SIZE, + //.reg_cache_default = wm8994_reg_defaults, + .reg_word_size = 2, + .compress_type = SND_SOC_RBTREE_COMPRESSION, +}; + +static int wm8994_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return snd_soc_register_codec(&client->dev, &soc_codec_dev_wm8994, + wm8994_dai, ARRAY_SIZE(wm8994_dai)); +} + +static int wm8994_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + + +static const struct i2c_device_id wm8994_i2c_id[] = { + {"wm8994-samsung", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); + +static struct i2c_driver wm8994_i2c_driver = { + .driver = { + .name = "wm8994-samsung-codec", + .owner = THIS_MODULE, + }, + .probe = wm8994_i2c_probe, + .remove = wm8994_i2c_remove, + .id_table = wm8994_i2c_id, +}; + +static __init int wm8994_driver_init(void) +{ + return i2c_add_driver(&wm8994_i2c_driver); +} +module_init(wm8994_driver_init); + +static __exit void wm8994_driver_exit(void) +{ + i2c_del_driver(&wm8994_i2c_driver); +} +module_exit(wm8994_driver_exit); MODULE_DESCRIPTION("ASoC WM8994 driver"); MODULE_AUTHOR("Shaju Abraham shaju.abraham@samsung.com"); diff --git a/sound/soc/codecs/wm8994_samsung.h b/sound/soc/codecs/wm8994_samsung.h index 0950b86..fa4fc3f 100755 --- a/sound/soc/codecs/wm8994_samsung.h +++ b/sound/soc/codecs/wm8994_samsung.h @@ -12,8 +12,6 @@ #include <sound/soc.h> #include <linux/mfd/wm8994/wm8994_pdata.h> -extern struct snd_soc_codec_device soc_codec_dev_wm8994; - /* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */ #define WM8994_SYSCLK_MCLK1 1 #define WM8994_SYSCLK_MCLK2 2 @@ -27,11 +25,11 @@ extern struct snd_soc_codec_device soc_codec_dev_wm8994; #include "wm8994_def.h" -extern struct snd_soc_dai wm8994_dai; - #define WM8994_SYSCLK_MCLK 1 #define WM8994_SYSCLK_FLL 2 +//#define WM8994_CACHE_SIZE 1570 + #define AUDIO_COMMON_DEBUG 0 #define DEACTIVE 0x00 @@ -136,7 +134,7 @@ enum wm8994_dc_servo_slots { }; struct wm8994_priv { - struct snd_soc_codec codec; + struct snd_soc_codec *codec; int master; int sysclk_source; unsigned int mclk_rate; diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index d155cbb..8601d70 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -20,6 +20,9 @@ config SND_S3C2412_SOC_I2S select SND_S3C_I2SV2_SOC select S3C2410_DMA +config SND_S5PC1XX_I2S + tristate + config SND_SAMSUNG_PCM tristate @@ -34,6 +37,12 @@ config SND_SAMSUNG_SPDIF config SND_SAMSUNG_I2S tristate +config S5P_INTERNAL_DMA + tristate + +config SND_S5P_WM8994_MASTER + bool + config SND_SOC_SAMSUNG_NEO1973_WM8753 tristate "Audio support for Openmoko Neo1973 Smartphones (GTA01/GTA02)" depends on SND_SOC_SAMSUNG && (MACH_NEO1973_GTA01 || MACH_NEO1973_GTA02) @@ -125,6 +134,17 @@ config SND_SOC_SAMSUNG_H1940_UDA1380 help This driver provides audio support for HP iPAQ h1940 PDA. +config SND_SOC_SAMSUNG_HERRING_WM8994 + tristate "SoC I2S Audio support for HERRING - WM8994" + depends on SND_SOC_SAMSUNG && (MACH_HERRING) + select SND_S5PC1XX_I2S + select SND_SOC_WM8994_SAMSUNG + select S5P_INTERNAL_DMA + select SND_S5P_WM8994_MASTER + help + Say Y if you want to add support for SoC audio on herring + with the WM8994. + config SND_SOC_SAMSUNG_RX1950_UDA1380 tristate "Audio support for the HP iPAQ RX1950" depends on SND_SOC_SAMSUNG && MACH_RX1950 diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 683843a..98a007e 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -1,7 +1,8 @@ # S3c24XX Platform Support -snd-soc-s3c24xx-objs := dma.o +snd-soc-s3c24xx-objs := dma.o s3c-dma-wrapper.o snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o +snd-soc-s5pc1xx-i2s-objs := s5pc1xx-i2s.o snd-soc-ac97-objs := ac97.o snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o snd-soc-samsung-spdif-objs := spdif.o @@ -13,9 +14,11 @@ obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o +obj-$(CONFIG_SND_S5PC1XX_I2S) += snd-soc-s5pc1xx-i2s.o obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o obj-$(CONFIG_SND_SAMSUNG_PCM) += snd-soc-pcm.o obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o +obj-$(CONFIG_S5P_INTERNAL_DMA) += s3c-idma.o s5p-i2s_sec.o # S3C24XX Machine Support snd-soc-jive-wm8750-objs := jive_wm8750.o @@ -33,6 +36,7 @@ snd-soc-smdk-wm8994-objs := smdk_wm8994.o snd-soc-smdk-wm9713-objs := smdk_wm9713.o snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o snd-soc-goni-wm8994-objs := goni_wm8994.o +snd-soc-herring-wm8994-objs := herring-wm8994.o snd-soc-smdk-spdif-objs := smdk_spdif.o snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o snd-soc-speyside-objs := speyside.o @@ -46,6 +50,7 @@ obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC) += snd-soc-s3c24xx-simtec.o obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o obj-$(CONFIG_SND_SOC_SAMSUNG_H1940_UDA1380) += snd-soc-h1940-uda1380.o +obj-$(CONFIG_SND_SOC_SAMSUNG_HERRING_WM8994) += snd-soc-herring-wm8994.o obj-$(CONFIG_SND_SOC_SAMSUNG_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994) += snd-soc-smdk-wm8994.o diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index 552bf43..fc56ed0 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c @@ -413,7 +413,11 @@ static void dma_free_dma_buffers(struct snd_pcm *pcm) pr_debug("Entered %s\n", __func__); +#ifdef CONFIG_S5P_INTERNAL_DMA + for (stream = 1; stream < 2; stream++) { +#else for (stream = 0; stream < 2; stream++) { +#endif substream = pcm->streams[stream].substream; if (!substream) continue; @@ -442,13 +446,14 @@ static int dma_new(struct snd_card *card, if (!card->dev->coherent_dma_mask) card->dev->coherent_dma_mask = 0xffffffff; +#ifndef CONFIG_S5P_INTERNAL_DMA if (dai->driver->playback.channels_min) { ret = preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); if (ret) goto out; } - +#endif if (dai->driver->capture.channels_min) { ret = preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); @@ -459,11 +464,14 @@ out: return ret; } -static struct snd_soc_platform_driver samsung_asoc_platform = { +struct snd_soc_platform_driver samsung_asoc_platform = { .ops = &dma_ops, .pcm_new = dma_new, .pcm_free = dma_free_dma_buffers, }; +EXPORT_SYMBOL_GPL(samsung_asoc_platform); + +#ifndef CONFIG_S5P_INTERNAL_DMA static int __devinit samsung_asoc_platform_probe(struct platform_device *pdev) { @@ -498,6 +506,8 @@ static void __exit samsung_asoc_exit(void) } module_exit(samsung_asoc_exit); +#endif + MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); MODULE_DESCRIPTION("Samsung ASoC DMA Driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index c506592..2bb0d44 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h @@ -19,4 +19,6 @@ struct s3c_dma_params { int dma_size; /* Size of the DMA transfer */ }; +extern struct snd_soc_platform_driver samsung_asoc_platform; + #endif diff --git a/sound/soc/samsung/herring-wm8994.c b/sound/soc/samsung/herring-wm8994.c index c4707e2..5f9dfe2 100644 --- a/sound/soc/samsung/herring-wm8994.c +++ b/sound/soc/samsung/herring-wm8994.c @@ -21,7 +21,7 @@ #include "../codecs/wm8994.h" #include "s3c-dma.h" #include "s5pc1xx-i2s.h" -#include "s3c-i2s-v2.h" +//#include "s3c-i2s-v2.h" #include <linux/io.h> @@ -42,8 +42,8 @@ int smdkc110_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->dai->cpu_dai; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; int bfs, rfs, ret; u32 ap_codec_clk; #ifndef CONFIG_SND_S5P_WM8994_MASTER @@ -290,20 +290,22 @@ static struct snd_soc_ops smdkc110_ops = { /* digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link smdkc1xx_dai = { - .name = "WM8994", + .name = "herring", .stream_name = "WM8994 HiFi Playback", - .cpu_dai = &s3c64xx_i2s_dai[I2S_NUM], - .codec_dai = &wm8994_dai, + .cpu_dai_name = "samsung-i2s.0", + .codec_dai_name = "WM8994 PAIFRX", + .platform_name = "samsung-audio", + .codec_name = "wm8994-samsung-codec.4-001a", .ops = &smdkc110_ops, }; static struct snd_soc_card smdkc100 = { .name = "smdkc110", - .platform = &s3c_dma_wrapper, .dai_link = &smdkc1xx_dai, .num_links = 1, }; +#if 0 static struct wm8994_setup_data smdkc110_wm8994_setup = { /* The I2C address of the WM89940 is 0x34. To the I2C driver @@ -319,6 +321,7 @@ static struct snd_soc_device smdkc1xx_snd_devdata = { .codec_dev = &soc_codec_dev_wm8994, .codec_data = &smdkc110_wm8994_setup, }; +#endif static struct platform_device *smdkc1xx_snd_device; static int __init smdkc110_audio_init(void) @@ -331,8 +334,7 @@ static int __init smdkc110_audio_init(void) if (!smdkc1xx_snd_device) return -ENOMEM; - platform_set_drvdata(smdkc1xx_snd_device, &smdkc1xx_snd_devdata); - smdkc1xx_snd_devdata.dev = &smdkc1xx_snd_device->dev; + platform_set_drvdata(smdkc1xx_snd_device, &smdkc100); ret = platform_device_add(smdkc1xx_snd_device); if (ret) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 992a732..a779185 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/regulator/consumer.h> #include <sound/soc.h> #include <sound/pcm_params.h> @@ -146,6 +147,8 @@ struct i2s_dai { unsigned rfs, bfs; /* I2S Controller's core clock */ struct clk *clk; + /* I2S Controller's power domain */ + struct regulator *regulator; /* Clock for generating I2S signals */ struct clk *op_clk; /* Array of clock names for op_clk */ @@ -572,9 +575,13 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct i2s_dai *i2s = to_info(dai); - u32 mod = readl(i2s->addr + I2SMOD); + u32 mod; u32 tmp = 0; + dev_info(&i2s->pdev->dev, "base %p\n", i2s->addr); + + mod = readl(i2s->addr + I2SMOD); + /* Format is priority */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_RIGHT_J: @@ -951,6 +958,9 @@ static int i2s_resume(struct snd_soc_dai *dai) static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) { + struct clk *fout_epll, *mout_epll; + struct clk *mout_audss = NULL; + struct clk *sclk_audio, *iis_clk, *iis_busclk, *iis_ipclk; /* these belong shomewhere else */ struct i2s_dai *i2s = to_info(dai); struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; @@ -971,6 +981,59 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) } clk_enable(i2s->clk); + /* Get i2s power domain regulator */ + i2s->regulator = regulator_get(&i2s->pdev->dev, "pd"); + if (IS_ERR(i2s->regulator)) { + dev_err(&i2s->pdev->dev, "%s: failed to get resource %s\n", + __func__, "i2s"); + return PTR_ERR(i2s->regulator); + } + + /* Enable Power domain */ + regulator_enable(i2s->regulator); + + fout_epll = clk_get(&i2s->pdev->dev, "fout_epll"); + if (IS_ERR(fout_epll)) + dev_err(&i2s->pdev->dev, "failed to get fout_epll\n"); + + mout_epll = clk_get(&i2s->pdev->dev, "mout_epll"); + if (IS_ERR(mout_epll)) + dev_err(&i2s->pdev->dev, "failed to get mout_epll\n"); + clk_set_parent(mout_epll, fout_epll); + + sclk_audio = clk_get(&i2s->pdev->dev, "sclk_audio"); + if (IS_ERR(sclk_audio)) + dev_err(&i2s->pdev->dev, "failed to get sclk_audio\n"); + clk_set_parent(sclk_audio, mout_epll); + + /* Need not to enable in general */ + clk_enable(sclk_audio); + + /* When I2S V5.1 used, initialize audio subsystem clock */ + /* CLKMUX_ASS */ + if (&i2s->pdev->id == 0) { + mout_audss = clk_get(NULL, "mout_audss"); + if (IS_ERR(mout_audss)) + dev_err(&i2s->pdev->dev, "failed to get mout_audss\n"); + clk_set_parent(mout_audss, fout_epll); + /*MUX-I2SA*/ + iis_clk = clk_get(&i2s->pdev->dev, "audio-bus"); + if (IS_ERR(iis_clk)) + dev_err(&i2s->pdev->dev, "failed to get audio-bus\n"); + clk_set_parent(iis_clk, mout_audss); + /*getting AUDIO BUS CLK*/ + iis_busclk = clk_get(NULL, "dout_audio_bus_clk_i2s"); + if (IS_ERR(iis_busclk)) + printk(KERN_ERR "failed to get audss_hclk\n"); + iis_ipclk = clk_get(&i2s->pdev->dev, "i2s_v50"); + if (IS_ERR(iis_ipclk)) + dev_err(&i2s->pdev->dev, "failed to get i2s_v50_clock\n"); + clk_enable(iis_ipclk); + clk_enable(iis_clk); + clk_enable(iis_busclk); + } + + if (other) { other->addr = i2s->addr; other->clk = i2s->clk; diff --git a/sound/soc/samsung/s3c-dma-wrapper.c b/sound/soc/samsung/s3c-dma-wrapper.c index 8f371eb..2f87b68 100644 --- a/sound/soc/samsung/s3c-dma-wrapper.c +++ b/sound/soc/samsung/s3c-dma-wrapper.c @@ -11,125 +11,125 @@ */ #include <sound/soc.h> -#include "s3c-dma.h" +#include "dma.h" #include "s3c-idma.h" static int s3c_wrpdma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_platform *platform; + struct snd_soc_platform_driver *platform; #ifdef CONFIG_S5P_INTERNAL_DMA if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) platform = &idma_soc_platform; else #endif - platform = &s3c24xx_soc_platform; + platform = &samsung_asoc_platform; - if (platform->pcm_ops->hw_params) - return platform->pcm_ops->hw_params(substream, params); + if (platform->ops->hw_params) + return platform->ops->hw_params(substream, params); else return 0; } static int s3c_wrpdma_hw_free(struct snd_pcm_substream *substream) { - struct snd_soc_platform *platform; + struct snd_soc_platform_driver *platform; #ifdef CONFIG_S5P_INTERNAL_DMA if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) platform = &idma_soc_platform; else #endif - platform = &s3c24xx_soc_platform; + platform = &samsung_asoc_platform; - if (platform->pcm_ops->hw_free) - return platform->pcm_ops->hw_free(substream); + if (platform->ops->hw_free) + return platform->ops->hw_free(substream); else return 0; } static int s3c_wrpdma_prepare(struct snd_pcm_substream *substream) { - struct snd_soc_platform *platform; + struct snd_soc_platform_driver *platform; #ifdef CONFIG_S5P_INTERNAL_DMA if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) platform = &idma_soc_platform; else #endif - platform = &s3c24xx_soc_platform; + platform = &samsung_asoc_platform; - if (platform->pcm_ops->prepare) - return platform->pcm_ops->prepare(substream); + if (platform->ops->prepare) + return platform->ops->prepare(substream); else return 0; } static int s3c_wrpdma_trigger(struct snd_pcm_substream *substream, int cmd) { - struct snd_soc_platform *platform; + struct snd_soc_platform_driver *platform; #ifdef CONFIG_S5P_INTERNAL_DMA if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) platform = &idma_soc_platform; else #endif - platform = &s3c24xx_soc_platform; + platform = &samsung_asoc_platform; - if (platform->pcm_ops->trigger) - return platform->pcm_ops->trigger(substream, cmd); + if (platform->ops->trigger) + return platform->ops->trigger(substream, cmd); else return 0; } static snd_pcm_uframes_t s3c_wrpdma_pointer(struct snd_pcm_substream *substream) { - struct snd_soc_platform *platform; + struct snd_soc_platform_driver *platform; #ifdef CONFIG_S5P_INTERNAL_DMA if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) platform = &idma_soc_platform; else #endif - platform = &s3c24xx_soc_platform; + platform = &samsung_asoc_platform; - if (platform->pcm_ops->pointer) - return platform->pcm_ops->pointer(substream); + if (platform->ops->pointer) + return platform->ops->pointer(substream); else return 0; } static int s3c_wrpdma_open(struct snd_pcm_substream *substream) { - struct snd_soc_platform *platform; + struct snd_soc_platform_driver *platform; #ifdef CONFIG_S5P_INTERNAL_DMA if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) platform = &idma_soc_platform; else #endif - platform = &s3c24xx_soc_platform; + platform = &samsung_asoc_platform; - if (platform->pcm_ops->open) - return platform->pcm_ops->open(substream); + if (platform->ops->open) + return platform->ops->open(substream); else return 0; } static int s3c_wrpdma_close(struct snd_pcm_substream *substream) { - struct snd_soc_platform *platform; + struct snd_soc_platform_driver *platform; #ifdef CONFIG_S5P_INTERNAL_DMA if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) platform = &idma_soc_platform; else #endif - platform = &s3c24xx_soc_platform; + platform = &samsung_asoc_platform; - if (platform->pcm_ops->close) - return platform->pcm_ops->close(substream); + if (platform->ops->close) + return platform->ops->close(substream); else return 0; } @@ -137,17 +137,17 @@ static int s3c_wrpdma_close(struct snd_pcm_substream *substream) static int s3c_wrpdma_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) { - struct snd_soc_platform *platform; + struct snd_soc_platform_driver *platform; #ifdef CONFIG_S5P_INTERNAL_DMA if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) platform = &idma_soc_platform; else #endif - platform = &s3c24xx_soc_platform; + platform = &samsung_asoc_platform; - if (platform->pcm_ops->ioctl) - return platform->pcm_ops->ioctl(substream, cmd, arg); + if (platform->ops->ioctl) + return platform->ops->ioctl(substream, cmd, arg); else return 0; } @@ -155,17 +155,17 @@ static int s3c_wrpdma_ioctl(struct snd_pcm_substream *substream, static int s3c_wrpdma_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { - struct snd_soc_platform *platform; + struct snd_soc_platform_driver *platform; #ifdef CONFIG_S5P_INTERNAL_DMA if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) platform = &idma_soc_platform; else #endif - platform = &s3c24xx_soc_platform; + platform = &samsung_asoc_platform; - if (platform->pcm_ops->mmap) - return platform->pcm_ops->mmap(substream, vma); + if (platform->ops->mmap) + return platform->ops->mmap(substream, vma); else return 0; } @@ -184,9 +184,9 @@ static struct snd_pcm_ops s3c_wrpdma_ops = { static void s3c_wrpdma_pcm_free(struct snd_pcm *pcm) { - struct snd_soc_platform *gdma_platform; + struct snd_soc_platform_driver *gdma_platform; #ifdef CONFIG_S5P_INTERNAL_DMA - struct snd_soc_platform *idma_platform; + struct snd_soc_platform_driver *idma_platform; #endif #ifdef CONFIG_S5P_INTERNAL_DMA @@ -194,7 +194,7 @@ static void s3c_wrpdma_pcm_free(struct snd_pcm *pcm) if (idma_platform->pcm_free) idma_platform->pcm_free(pcm); #endif - gdma_platform = &s3c24xx_soc_platform; + gdma_platform = &samsung_asoc_platform; if (gdma_platform->pcm_free) gdma_platform->pcm_free(pcm); } @@ -202,9 +202,9 @@ static void s3c_wrpdma_pcm_free(struct snd_pcm *pcm) static int s3c_wrpdma_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm) { - struct snd_soc_platform *gdma_platform; + struct snd_soc_platform_driver *gdma_platform; #ifdef CONFIG_S5P_INTERNAL_DMA - struct snd_soc_platform *idma_platform; + struct snd_soc_platform_driver *idma_platform; #endif /* sec_fifo i/f always use internal h/w buffers @@ -215,30 +215,50 @@ static int s3c_wrpdma_pcm_new(struct snd_card *card, if (idma_platform->pcm_new) idma_platform->pcm_new(card, dai, pcm); #endif - gdma_platform = &s3c24xx_soc_platform; + gdma_platform = &samsung_asoc_platform; if (gdma_platform->pcm_new) gdma_platform->pcm_new(card, dai, pcm); return 0; } -struct snd_soc_platform s3c_dma_wrapper = { - .name = "samsung-audio", - .pcm_ops = &s3c_wrpdma_ops, +static struct snd_soc_platform_driver s3c_dma_wrapper = { + .ops = &s3c_wrpdma_ops, .pcm_new = s3c_wrpdma_pcm_new, .pcm_free = s3c_wrpdma_pcm_free, }; -EXPORT_SYMBOL_GPL(s3c_dma_wrapper); +//EXPORT_SYMBOL_GPL(s3c_dma_wrapper); + +static int __devinit s3c_dma_wrapper_platform_probe(struct platform_device *pdev) +{ + return snd_soc_register_platform(&pdev->dev, &s3c_dma_wrapper); +} + +static int __devexit s3c_dma_wrapper_platform_remove(struct platform_device *pdev) +{ + snd_soc_unregister_platform(&pdev->dev); + return 0; +} + +static struct platform_driver s3c_dma_wrapper_driver = { + .driver = { + .name = "samsung-audio", + .owner = THIS_MODULE, + }, + + .probe = s3c_dma_wrapper_platform_probe, + .remove = __devexit_p(s3c_dma_wrapper_platform_remove), +}; static int __init s3c_dma_wrapper_init(void) { - return snd_soc_register_platform(&s3c_dma_wrapper); + return platform_driver_register(&s3c_dma_wrapper_driver); } module_init(s3c_dma_wrapper_init); static void __exit s3c_dma_wrapper_exit(void) { - snd_soc_unregister_platform(&s3c_dma_wrapper); + platform_driver_unregister(&s3c_dma_wrapper_driver); } module_exit(s3c_dma_wrapper_exit); diff --git a/sound/soc/samsung/s3c-dma.c b/sound/soc/samsung/s3c-dma.c index 765cea1..8985964 100644 --- a/sound/soc/samsung/s3c-dma.c +++ b/sound/soc/samsung/s3c-dma.c @@ -147,7 +147,7 @@ static int s3c_dma_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; unsigned long totbytes = params_buffer_bytes(params); struct s3c_dma_params *dma = - snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream); + snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); int ret = 0; @@ -449,14 +449,14 @@ static int s3c_dma_new(struct snd_card *card, if (!card->dev->coherent_dma_mask) card->dev->coherent_dma_mask = 0xffffffff; #ifndef CONFIG_S5P_INTERNAL_DMA - if (dai->playback.channels_min) { + if (dai->driver->playback.channels_min) { ret = s3c_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); if (ret) goto out; } #endif - if (dai->capture.channels_min) { + if (dai->driver->capture.channels_min) { ret = s3c_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); if (ret) @@ -466,9 +466,8 @@ static int s3c_dma_new(struct snd_card *card, return ret; } -struct snd_soc_platform s3c24xx_soc_platform = { - .name = "s3c24xx-audio", - .pcm_ops = &s3c_dma_ops, +struct snd_soc_platform_driver s3c24xx_soc_platform = { + .ops = &s3c_dma_ops, .pcm_new = s3c_dma_new, .pcm_free = s3c_dma_free_dma_buffers, }; diff --git a/sound/soc/samsung/s3c-dma.h b/sound/soc/samsung/s3c-dma.h index d2bed08..cb869db 100644 --- a/sound/soc/samsung/s3c-dma.h +++ b/sound/soc/samsung/s3c-dma.h @@ -26,7 +26,7 @@ struct s3c_dma_params { //#define pr_debug(fmt...) printk(fmt) /* platform data */ -extern struct snd_soc_platform s3c24xx_soc_platform; +extern struct snd_soc_platform_driver s3c24xx_soc_platform; extern struct snd_soc_platform s3c24xx_pcm_soc_platform; extern struct snd_ac97_bus_ops s3c24xx_ac97_ops; diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c index 5179b73..52074a2b 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c @@ -1,4 +1,4 @@ -/* sound/soc/s3c24xx/s3c-i2c-v2.c +/* sound/soc/samsung/s3c-i2c-v2.c * * ALSA Soc Audio Layer - I2S core for newer Samsung SoCs. * @@ -16,34 +16,27 @@ * option) any later version. */ -#include <linux/init.h> -#include <linux/module.h> -#include <linux/device.h> #include <linux/delay.h> #include <linux/clk.h> -#include <linux/kernel.h> #include <linux/io.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/initval.h> #include <sound/soc.h> - -#include <plat/regs-iis.h> +#include <sound/pcm_params.h> #include <mach/dma.h> +#include "regs-i2s-v2.h" #include "s3c-i2s-v2.h" -#include "s3c-dma.h" +#include "dma.h" #undef S3C_IIS_V2_SUPPORTED -#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) \ + || defined(CONFIG_CPU_S5PV210) #define S3C_IIS_V2_SUPPORTED #endif -#if defined(CONFIG_PLAT_S3C64XX) || defined(CONFIG_PLAT_S5P) +#ifdef CONFIG_PLAT_S3C64XX #define S3C_IIS_V2_SUPPORTED #endif @@ -55,7 +48,7 @@ static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) { - return cpu_dai->private_data; + return snd_soc_dai_get_drvdata(cpu_dai); } #define bit_set(v, b) (((v) & (b)) ? 1 : 0) @@ -133,12 +126,8 @@ static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) */ con |= S3C2412_IISCON_TXDMA_PAUSE; - con &= ~S3C2412_IISCON_TXDMA_ACTIVE; - if (con & S5P_IISCON_TXSDMACTIVE) { /* If sec is active */ - writel(con, regs + S3C2412_IISCON); - return; - } con |= S3C2412_IISCON_TXCH_PAUSE; + con &= ~S3C2412_IISCON_TXDMA_ACTIVE; switch (mod & S3C2412_IISMOD_MODE_MASK) { case S3C2412_IISMOD_MODE_TXRX: @@ -276,35 +265,14 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, iismod = readl(i2s->regs + S3C2412_IISMOD); pr_debug("hw_params r: IISMOD: %x \n", iismod); -#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) -#define IISMOD_MASTER_MASK S3C2412_IISMOD_MASTER_MASK -#define IISMOD_SLAVE S3C2412_IISMOD_SLAVE -#define IISMOD_MASTER S3C2412_IISMOD_MASTER_INTERNAL -#endif - -#if defined(CONFIG_PLAT_S3C64XX) || defined(CONFIG_PLAT_S5P) -/* From Rev1.1 datasheet, we have two master and two slave modes: - * IMS[11:10]: - * 00 = master mode, fed from PCLK - * 01 = master mode, fed from CLKAUDIO - * 10 = slave mode, using PCLK - * 11 = slave mode, using I2SCLK - */ -#define IISMOD_MASTER_MASK (1 << 11) -#define IISMOD_SLAVE (1 << 11) -#define IISMOD_MASTER (0 << 11) -#endif - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: i2s->master = 0; - iismod &= ~IISMOD_MASTER_MASK; - iismod |= IISMOD_SLAVE; + iismod |= S3C2412_IISMOD_SLAVE; break; case SND_SOC_DAIFMT_CBS_CFS: i2s->master = 1; - iismod &= ~IISMOD_MASTER_MASK; - iismod |= IISMOD_MASTER; + iismod &= ~S3C2412_IISMOD_SLAVE; break; default: pr_err("unknwon master/slave format\n"); @@ -336,91 +304,114 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, return 0; } -int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, +static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, - struct snd_soc_dai *socdai) + struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai_link *dai = rtd->dai; - struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai); + struct s3c_i2sv2_info *i2s = to_info(dai); + struct s3c_dma_params *dma_data; u32 iismod; pr_debug("Entered %s\n", __func__); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream,i2s->dma_playback); + dma_data = i2s->dma_playback; else - snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream,i2s->dma_capture); + dma_data = i2s->dma_capture; + + snd_soc_dai_set_dma_data(dai, substream, dma_data); /* Working copies of register */ iismod = readl(i2s->regs + S3C2412_IISMOD); pr_debug("%s: r: IISMOD: %x\n", __func__, iismod); - switch(params_channels(params)){ - case 1: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - i2s->dma_playback->dma_size = 2; - else - i2s->dma_capture->dma_size = 2; - break; - case 2: - break; - default: - break; - } -#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) + iismod &= ~S3C64XX_IISMOD_BLC_MASK; + /* Sample size */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: - iismod |= S3C2412_IISMOD_8BIT; + iismod |= S3C64XX_IISMOD_BLC_8BIT; break; case SNDRV_PCM_FORMAT_S16_LE: - iismod &= ~S3C2412_IISMOD_8BIT; + break; + case SNDRV_PCM_FORMAT_S24_LE: + iismod |= S3C64XX_IISMOD_BLC_24BIT; break; } -#endif -#if defined(CONFIG_PLAT_S3C64XX) || defined(CONFIG_PLAT_S5P) - iismod &= ~(S3C64XX_IISMOD_BLC_MASK | S3C2412_IISMOD_BCLK_MASK); - /* Sample size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S8: - /* 8 bit sample, 16fs BCLK */ - iismod |= (S3C64XX_IISMOD_BLC_8BIT | S3C2412_IISMOD_BCLK_16FS); + writel(iismod, i2s->regs + S3C2412_IISMOD); + pr_debug("%s: w: IISMOD: %x\n", __func__, iismod); + + return 0; +} + +static int s3c_i2sv2_set_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + struct s3c_i2sv2_info *i2s = to_info(cpu_dai); + u32 iismod = readl(i2s->regs + S3C2412_IISMOD); + + pr_debug("Entered %s\n", __func__); + pr_debug("%s r: IISMOD: %x\n", __func__, iismod); + + switch (clk_id) { + case S3C_I2SV2_CLKSRC_PCLK: + iismod &= ~S3C2412_IISMOD_IMS_SYSMUX; break; - case SNDRV_PCM_FORMAT_S16_LE: - /* 16 bit sample, 32fs BCLK */ + + case S3C_I2SV2_CLKSRC_AUDIOBUS: + iismod |= S3C2412_IISMOD_IMS_SYSMUX; break; - case SNDRV_PCM_FORMAT_S24_LE: - /* 24 bit sample, 48fs BCLK */ - iismod |= (S3C64XX_IISMOD_BLC_24BIT | S3C2412_IISMOD_BCLK_48FS); + + case S3C_I2SV2_CLKSRC_CDCLK: + /* Error if controller doesn't have the CDCLKCON bit */ + if (!(i2s->feature & S3C_FEATURE_CDCLKCON)) + return -EINVAL; + + switch (dir) { + case SND_SOC_CLOCK_IN: + iismod |= S3C64XX_IISMOD_CDCLKCON; + break; + case SND_SOC_CLOCK_OUT: + iismod &= ~S3C64XX_IISMOD_CDCLKCON; + break; + default: + return -EINVAL; + } break; - } - /* Set the IISMOD[25:24](BLC_P) to same value */ - iismod &= ~(S5P_IISMOD_BLCPMASK); - iismod |= ((iismod & S3C64XX_IISMOD_BLC_MASK) << 11); -#endif + default: + return -EINVAL; + } writel(iismod, i2s->regs + S3C2412_IISMOD); - pr_debug("%s: w: IISMOD: %x\n", __func__, iismod); + pr_debug("%s w: IISMOD: %x\n", __func__, iismod); + return 0; } -EXPORT_SYMBOL_GPL(s3c2412_i2s_hw_params); -int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, +static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct s3c_i2sv2_info *i2s = to_info(rtd->dai->cpu_dai); + struct s3c_i2sv2_info *i2s = to_info(rtd->cpu_dai); int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); unsigned long irqs; int ret = 0; + struct s3c_dma_params *dma_data = + snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); pr_debug("Entered %s\n", __func__); switch (cmd) { case SNDRV_PCM_TRIGGER_START: + /* On start, ensure that the FIFOs are cleared and reset. */ + + writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH, + i2s->regs + S3C2412_IISFIC); + + /* clear again, just in case */ + writel(0x0, i2s->regs + S3C2412_IISFIC); + case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (!i2s->master) { @@ -437,6 +428,14 @@ int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, s3c2412_snd_txctrl(i2s, 1); local_irq_restore(irqs); + + /* + * Load the next buffer to DMA to meet the reqirement + * of the auto reload mechanism of S3C24XX. + * This call won't bother S3C64XX. + */ + s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED); + break; case SNDRV_PCM_TRIGGER_STOP: @@ -459,7 +458,6 @@ int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, exit_err: return ret; } -EXPORT_SYMBOL_GPL(s3c2412_i2s_trigger); /* * Set S3C2412 Clock dividers @@ -474,29 +472,25 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, switch (div_id) { case S3C_I2SV2_DIV_BCLK: - if (div > 3) { - /* convert value to bit field */ - - switch (div) { - case 16: - div = S3C2412_IISMOD_BCLK_16FS; - break; + switch (div) { + case 16: + div = S3C2412_IISMOD_BCLK_16FS; + break; - case 32: - div = S3C2412_IISMOD_BCLK_32FS; - break; + case 32: + div = S3C2412_IISMOD_BCLK_32FS; + break; - case 24: - div = S3C2412_IISMOD_BCLK_24FS; - break; + case 24: + div = S3C2412_IISMOD_BCLK_24FS; + break; - case 48: - div = S3C2412_IISMOD_BCLK_48FS; - break; + case 48: + div = S3C2412_IISMOD_BCLK_48FS; + break; - default: - return -EINVAL; - } + default: + return -EINVAL; } reg = readl(i2s->regs + S3C2412_IISMOD); @@ -507,29 +501,25 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, break; case S3C_I2SV2_DIV_RCLK: - if (div > 3) { - /* convert value to bit field */ - - switch (div) { - case 256: - div = S3C2412_IISMOD_RCLK_256FS; - break; + switch (div) { + case 256: + div = S3C2412_IISMOD_RCLK_256FS; + break; - case 384: - div = S3C2412_IISMOD_RCLK_384FS; - break; + case 384: + div = S3C2412_IISMOD_RCLK_384FS; + break; - case 512: - div = S3C2412_IISMOD_RCLK_512FS; - break; + case 512: + div = S3C2412_IISMOD_RCLK_512FS; + break; - case 768: - div = S3C2412_IISMOD_RCLK_768FS; - break; + case 768: + div = S3C2412_IISMOD_RCLK_768FS; + break; - default: - return -EINVAL; - } + default: + return -EINVAL; } reg = readl(i2s->regs + S3C2412_IISMOD); @@ -555,6 +545,33 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, return 0; } +static snd_pcm_sframes_t s3c2412_i2s_delay(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct s3c_i2sv2_info *i2s = to_info(dai); + u32 reg = readl(i2s->regs + S3C2412_IISFIC); + snd_pcm_sframes_t delay; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + delay = S3C2412_IISFIC_TXCOUNT(reg); + else + delay = S3C2412_IISFIC_RXCOUNT(reg); + + return delay; +} + +struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai) +{ + struct s3c_i2sv2_info *i2s = to_info(cpu_dai); + u32 iismod = readl(i2s->regs + S3C2412_IISMOD); + + if (iismod & S3C2412_IISMOD_IMS_SYSMUX) + return i2s->iis_cclk; + else + return i2s->iis_pclk; +} +EXPORT_SYMBOL_GPL(s3c_i2sv2_get_clock); + /* default table of all avaialable root fs divisors */ static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 }; @@ -620,18 +637,17 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, } EXPORT_SYMBOL_GPL(s3c_i2sv2_iis_calc_rate); -int s3c_i2sv2_probe(struct platform_device *pdev, - struct snd_soc_dai *dai, +int s3c_i2sv2_probe(struct snd_soc_dai *dai, struct s3c_i2sv2_info *i2s, unsigned long base) { - struct device *dev = &pdev->dev; + struct device *dev = dai->dev; unsigned int iismod; i2s->dev = dev; /* record our i2s structure for later use in the callbacks */ - dai->private_data = i2s; + snd_soc_dai_set_drvdata(dai, i2s); i2s->regs = ioremap(base, 0x100); if (i2s->regs == NULL) { @@ -639,10 +655,14 @@ int s3c_i2sv2_probe(struct platform_device *pdev, return -ENXIO; } + i2s->iis_pclk = clk_get(dev, "iis"); + if (IS_ERR(i2s->iis_pclk)) { + dev_err(dev, "failed to get iis_clock\n"); + iounmap(i2s->regs); + return -ENOENT; + } -#if defined(CONFIG_PLAT_S5P) - writel(((1<<0)|(1<<31)), i2s->regs + S3C2412_IISCON); -#endif + clk_enable(i2s->iis_pclk); /* Mark ourselves as in TXRX mode so we can run through our cleanup * process without warnings. */ @@ -657,35 +677,29 @@ int s3c_i2sv2_probe(struct platform_device *pdev, EXPORT_SYMBOL_GPL(s3c_i2sv2_probe); #ifdef CONFIG_PM - -#include <mach/map.h> -#define S3C_VA_AUDSS S3C_ADDR(0x01600000) /* Audio SubSystem */ -#include <mach/regs-audss.h> static int s3c2412_i2s_suspend(struct snd_soc_dai *dai) { struct s3c_i2sv2_info *i2s = to_info(dai); u32 iismod; - i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD); - i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON); - i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR); + if (dai->active) { + i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD); + i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON); + i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR); - /* Is this dai for I2Sv5? */ - if(dai->id == 0) - i2s->suspend_audss_clksrc = readl(S5P_CLKSRC_AUDSS); + /* some basic suspend checks */ - /* some basic suspend checks */ + iismod = readl(i2s->regs + S3C2412_IISMOD); - iismod = readl(i2s->regs + S3C2412_IISMOD); - - if (iismod & S3C2412_IISCON_RXDMA_ACTIVE) - pr_warning("%s: RXDMA active?\n", __func__); + if (iismod & S3C2412_IISCON_RXDMA_ACTIVE) + pr_warning("%s: RXDMA active?\n", __func__); - if (iismod & S3C2412_IISCON_TXDMA_ACTIVE) - pr_warning("%s: TXDMA active?\n", __func__); + if (iismod & S3C2412_IISCON_TXDMA_ACTIVE) + pr_warning("%s: TXDMA active?\n", __func__); - if (iismod & S3C2412_IISCON_IIS_ACTIVE) - pr_warning("%s: IIS active\n", __func__); + if (iismod & S3C2412_IISCON_IIS_ACTIVE) + pr_warning("%s: IIS active\n", __func__); + } return 0; } @@ -697,19 +711,17 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai) pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n", dai->active, i2s->suspend_iismod, i2s->suspend_iiscon); - writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON); - writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD); - writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR); + if (dai->active) { + writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON); + writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD); + writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR); - /* Is this dai for I2Sv5? */ - if(dai->id == 0) - writel(i2s->suspend_audss_clksrc, S5P_CLKSRC_AUDSS); + writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH, + i2s->regs + S3C2412_IISFIC); - writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH, - i2s->regs + S3C2412_IISFIC); - - ndelay(250); - writel(0x0, i2s->regs + S3C2412_IISFIC); + ndelay(250); + writel(0x0, i2s->regs + S3C2412_IISFIC); + } return 0; } @@ -718,19 +730,26 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai) #define s3c2412_i2s_resume NULL #endif -int s3c_i2sv2_register_dai(struct snd_soc_dai *dai) +int s3c_i2sv2_register_dai(struct device *dev, int id, + struct snd_soc_dai_driver *drv) { - struct snd_soc_dai_ops *ops = dai->ops; + struct snd_soc_dai_ops *ops = drv->ops; ops->trigger = s3c2412_i2s_trigger; - ops->hw_params = s3c2412_i2s_hw_params; + if (!ops->hw_params) + ops->hw_params = s3c_i2sv2_hw_params; ops->set_fmt = s3c2412_i2s_set_fmt; ops->set_clkdiv = s3c2412_i2s_set_clkdiv; + ops->set_sysclk = s3c_i2sv2_set_sysclk; + + /* Allow overriding by (for example) IISv4 */ + if (!ops->delay) + ops->delay = s3c2412_i2s_delay; - dai->suspend = s3c2412_i2s_suspend; - dai->resume = s3c2412_i2s_resume; + drv->suspend = s3c2412_i2s_suspend; + drv->resume = s3c2412_i2s_resume; - return snd_soc_register_dai(dai); + return snd_soc_register_dai(dev, drv); } EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai); diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h index f77e0ad..f8297d9 100644 --- a/sound/soc/samsung/s3c-i2s-v2.h +++ b/sound/soc/samsung/s3c-i2s-v2.h @@ -1,4 +1,4 @@ -/* sound/soc/s3c24xx/s3c-i2s-v2.h +/* sound/soc/samsung/s3c-i2s-v2.h * * ALSA Soc Audio Layer - S3C_I2SV2 I2S driver * @@ -25,10 +25,20 @@ #define S3C_I2SV2_DIV_RCLK (2) #define S3C_I2SV2_DIV_PRESCALER (3) +#define S3C_I2SV2_CLKSRC_PCLK 0 +#define S3C_I2SV2_CLKSRC_AUDIOBUS 1 +#define S3C_I2SV2_CLKSRC_CDCLK 2 + +/* Set this flag for I2S controllers that have the bit IISMOD[12] + * bridge/break RCLK signal and external Xi2sCDCLK pin. + */ +#define S3C_FEATURE_CDCLKCON (1 << 0) + /** * struct s3c_i2sv2_info - S3C I2S-V2 information * @dev: The parent device passed to use from the probe. * @regs: The pointer to the device registe block. + * @feature: Set of bit-flags indicating features of the controller. * @master: True if the I2S core is the I2S bit clock master. * @dma_playback: DMA information for playback channel. * @dma_capture: DMA information for capture channel. @@ -43,12 +53,10 @@ struct s3c_i2sv2_info { struct device *dev; void __iomem *regs; - struct clk *sclk_audio; - struct clk *iis_ipclk; + u32 feature; + + struct clk *iis_pclk; struct clk *iis_cclk; - struct clk *iis_clk; - struct clk *iis_busclk; - struct regulator *regulator; unsigned char master; @@ -58,12 +66,12 @@ struct s3c_i2sv2_info { u32 suspend_iismod; u32 suspend_iiscon; u32 suspend_iispsr; - u32 suspend_iisahb; - u32 suspend_audss_clksrc; - u32 suspend_audss_clkdiv; - u32 suspend_audss_clkgate; + + unsigned long base; }; +extern struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai); + struct s3c_i2sv2_rate_calc { unsigned int clk_div; /* for prescaler */ unsigned int fs_div; /* for root frame clock */ @@ -75,23 +83,24 @@ extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, /** * s3c_i2sv2_probe - probe for i2s device helper - * @pdev: The platform device supplied to the original probe. * @dai: The ASoC DAI structure supplied to the original probe. * @i2s: Our local i2s structure to fill in. * @base: The base address for the registers. */ -extern int s3c_i2sv2_probe(struct platform_device *pdev, - struct snd_soc_dai *dai, +extern int s3c_i2sv2_probe(struct snd_soc_dai *dai, struct s3c_i2sv2_info *i2s, unsigned long base); /** * s3c_i2sv2_register_dai - register dai with soc core - * @dai: The snd_soc_dai structure to register + * @dev: DAI device + * @id: DAI ID + * @drv: The driver structure to register * * Fill in any missing fields and then register the given dai with the * soc core. */ -extern int s3c_i2sv2_register_dai(struct snd_soc_dai *dai); +extern int s3c_i2sv2_register_dai(struct device *dev, int id, + struct snd_soc_dai_driver *drv); #endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */ diff --git a/sound/soc/samsung/s3c-idma.c b/sound/soc/samsung/s3c-idma.c index 08fcc0d..c3b8c74 100644 --- a/sound/soc/samsung/s3c-idma.c +++ b/sound/soc/samsung/s3c-idma.c @@ -508,16 +508,15 @@ static int s3c_idma_pcm_new(struct snd_card *card, if (!card->dev->coherent_dma_mask) card->dev->coherent_dma_mask = DMA_BIT_MASK(32); - if (dai->playback.channels_min) + if (dai->driver->playback.channels_min) ret = s3c_idma_preallocate_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); return ret; } -struct snd_soc_platform idma_soc_platform = { - .name = "s5p-lp-audio", - .pcm_ops = &s3c_idma_ops, +struct snd_soc_platform_driver idma_soc_platform = { + .ops = &s3c_idma_ops, .pcm_new = s3c_idma_pcm_new, .pcm_free = s3c_idma_pcm_free, }; diff --git a/sound/soc/samsung/s3c-idma.h b/sound/soc/samsung/s3c-idma.h index 2c89230..351c3c3 100644 --- a/sound/soc/samsung/s3c-idma.h +++ b/sound/soc/samsung/s3c-idma.h @@ -29,7 +29,9 @@ #define LPAM_DMA_STOP 0 #define LPAM_DMA_START 1 -extern struct snd_soc_platform idma_soc_platform; +extern struct snd_soc_platform_driver idma_soc_platform; extern int i2s_trigger_stop; extern bool audio_clk_gated ; +void s5p_idma_init(void *regs); + #endif /* __S3C_IDMA_H_ */ diff --git a/sound/soc/samsung/s5p-i2s_sec.c b/sound/soc/samsung/s5p-i2s_sec.c index 59e9115..747dd1c 100644 --- a/sound/soc/samsung/s5p-i2s_sec.c +++ b/sound/soc/samsung/s5p-i2s_sec.c @@ -25,6 +25,7 @@ #include <mach/regs-audss.h> #include <mach/dma.h> #include "s3c-dma.h" +#include "s3c-idma.h" #include "s3c-i2s-v2.h" #define S3C64XX_DIV_BCLK S3C_I2SV2_DIV_BCLK @@ -49,7 +50,7 @@ static struct s3c_dma_params s5p_i2s_sec_pcm_out = { static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) { - return cpu_dai->private_data; + return snd_soc_dai_get_drvdata(cpu_dai); } static void s5p_snd_rxctrl(int on) @@ -226,7 +227,7 @@ int s5p_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; u32 iismod; - snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, + snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, &s5p_i2s_sec_pcm_out); iismod = readl(s5p_i2s0_regs + S3C2412_IISMOD); diff --git a/sound/soc/samsung/s5pc1xx-i2s.c b/sound/soc/samsung/s5pc1xx-i2s.c index ca738d9..674ccaa 100644 --- a/sound/soc/samsung/s5pc1xx-i2s.c +++ b/sound/soc/samsung/s5pc1xx-i2s.c @@ -21,6 +21,7 @@ #include <linux/regulator/consumer.h> #include <sound/soc.h> +#include <sound/pcm_params.h> #include <plat/regs-iis.h> #include <plat/audio.h> @@ -53,9 +54,9 @@ static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[MAX_I2SV3]; static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[MAX_I2SV3]; static struct s3c_i2sv2_info s3c64xx_i2s[MAX_I2SV3]; -struct snd_soc_dai s3c64xx_i2s_dai[MAX_I2SV3]; +static struct snd_soc_dai_driver s3c64xx_i2s_dai_driver[MAX_I2SV3]; bool audio_clk_gated; /* At first, clock & i2s0_pd is enabled in probe() */ -EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai); +//EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai); /* For I2S Clock/Power Gating */ static int tx_clk_enabled ; @@ -78,7 +79,7 @@ void dump_i2s(struct s3c_i2sv2_info *i2s) static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) { - return cpu_dai->private_data; + return snd_soc_dai_get_drvdata(cpu_dai); } struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai) @@ -123,6 +124,77 @@ void s5p_i2s_set_clk_enabled(struct snd_soc_dai *dai, bool state) } } +static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct s3c_i2sv2_info *i2s = to_info(dai); + u32 iismod; + + pr_debug("Entered %s\n", __func__); + + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dai_set_dma_data(dai, substream, + i2s->dma_playback); + else + snd_soc_dai_set_dma_data(dai, substream, + i2s->dma_capture); + + /* Working copies of register */ + iismod = readl(i2s->regs + S3C2412_IISMOD); + pr_debug("%s: r: IISMOD: %x\n", __func__, iismod); + + switch (params_channels(params)) { + case 1: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + i2s->dma_playback->dma_size = 2; + else + i2s->dma_capture->dma_size = 2; + break; + case 2: + break; + default: + break; + } +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + iismod |= S3C2412_IISMOD_8BIT; + break; + case SNDRV_PCM_FORMAT_S16_LE: + iismod &= ~S3C2412_IISMOD_8BIT; + break; + } +#endif + +#if defined(CONFIG_PLAT_S3C64XX) || defined(CONFIG_PLAT_S5P) + iismod &= ~(S3C64XX_IISMOD_BLC_MASK | S3C2412_IISMOD_BCLK_MASK); + /* Sample size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + /* 8 bit sample, 16fs BCLK */ + iismod |= (S3C64XX_IISMOD_BLC_8BIT | S3C2412_IISMOD_BCLK_16FS); + break; + case SNDRV_PCM_FORMAT_S16_LE: + /* 16 bit sample, 32fs BCLK */ + break; + case SNDRV_PCM_FORMAT_S24_LE: + /* 24 bit sample, 48fs BCLK */ + iismod |= (S3C64XX_IISMOD_BLC_24BIT | S3C2412_IISMOD_BCLK_48FS); + break; + } + + /* Set the IISMOD[25:24](BLC_P) to same value */ + iismod &= ~(S5P_IISMOD_BLCPMASK); + iismod |= ((iismod & S3C64XX_IISMOD_BLC_MASK) << 11); +#endif + + writel(iismod, i2s->regs + S3C2412_IISMOD); + pr_debug("%s: w: IISMOD: %x\n", __func__, iismod); + return 0; +} + static int s5p_i2s_wr_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -138,6 +210,264 @@ static int s5p_i2s_wr_hw_params(struct snd_pcm_substream *substream, #endif return 0; } + +#define S3C2412_I2S_DEBUG_CON 1 + +#define bit_set(v, b) (((v) & (b)) ? 1 : 0) + +#if S3C2412_I2S_DEBUG_CON +static void dbg_showcon(const char *fn, u32 con) +{ + printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d,\ + RXFFULL=%d\n", fn, + bit_set(con, S3C2412_IISCON_LRINDEX), + bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY), + bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY), + bit_set(con, S3C2412_IISCON_TXFIFO_FULL), + bit_set(con, S3C2412_IISCON_RXFIFO_FULL)); + + printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n", + fn, + bit_set(con, S3C2412_IISCON_TXDMA_PAUSE), + bit_set(con, S3C2412_IISCON_RXDMA_PAUSE), + bit_set(con, S3C2412_IISCON_TXCH_PAUSE), + bit_set(con, S3C2412_IISCON_RXCH_PAUSE)); + printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn, + bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE), + bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE), + bit_set(con, S3C2412_IISCON_IIS_ACTIVE)); +} +#else +static inline void dbg_showcon(const char *fn, u32 con) +{ +} +#endif + +/* Turn on or off the transmission path. */ +static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) +{ + void __iomem *regs = i2s->regs; + u32 fic, con, mod; + + pr_debug("%s(%d)\n", __func__, on); + + fic = readl(regs + S3C2412_IISFIC); + con = readl(regs + S3C2412_IISCON); + mod = readl(regs + S3C2412_IISMOD); + + pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); + + if (on) { + con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE; + con &= ~S3C2412_IISCON_TXDMA_PAUSE; + con &= ~S3C2412_IISCON_TXCH_PAUSE; + + switch (mod & S3C2412_IISMOD_MODE_MASK) { + case S3C2412_IISMOD_MODE_TXONLY: + case S3C2412_IISMOD_MODE_TXRX: + /* do nothing, we are in the right mode */ + break; + + case S3C2412_IISMOD_MODE_RXONLY: + mod &= ~S3C2412_IISMOD_MODE_MASK; + mod |= S3C2412_IISMOD_MODE_TXRX; + break; + + default: + dev_err(i2s->dev, "TXEN: Invalid MODE %x in IISMOD\n", + mod & S3C2412_IISMOD_MODE_MASK); + break; + } + + writel(con, regs + S3C2412_IISCON); + writel(mod, regs + S3C2412_IISMOD); + } else { + /* Note, we do not have any indication that the FIFO problems + * tha the S3C2410/2440 had apply here, so we should be able + * to disable the DMA and TX without resetting the FIFOS. + */ + + con |= S3C2412_IISCON_TXDMA_PAUSE; + con &= ~S3C2412_IISCON_TXDMA_ACTIVE; + if (con & S5P_IISCON_TXSDMACTIVE) { /* If sec is active */ + writel(con, regs + S3C2412_IISCON); + return; + } + con |= S3C2412_IISCON_TXCH_PAUSE; + + switch (mod & S3C2412_IISMOD_MODE_MASK) { + case S3C2412_IISMOD_MODE_TXRX: + mod &= ~S3C2412_IISMOD_MODE_MASK; + mod |= S3C2412_IISMOD_MODE_RXONLY; + break; + + case S3C2412_IISMOD_MODE_TXONLY: + mod &= ~S3C2412_IISMOD_MODE_MASK; + con &= ~S3C2412_IISCON_IIS_ACTIVE; + break; + + default: + dev_err(i2s->dev, "TXDIS: Invalid MODE %x in IISMOD\n", + mod & S3C2412_IISMOD_MODE_MASK); + break; + } + + writel(mod, regs + S3C2412_IISMOD); + writel(con, regs + S3C2412_IISCON); + } + + fic = readl(regs + S3C2412_IISFIC); + dbg_showcon(__func__, con); + pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); +} + +#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) + +static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) +{ + void __iomem *regs = i2s->regs; + u32 fic, con, mod; + + pr_debug("%s(%d)\n", __func__, on); + + fic = readl(regs + S3C2412_IISFIC); + con = readl(regs + S3C2412_IISCON); + mod = readl(regs + S3C2412_IISMOD); + + pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); + + if (on) { + con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE; + con &= ~S3C2412_IISCON_RXDMA_PAUSE; + con &= ~S3C2412_IISCON_RXCH_PAUSE; + + switch (mod & S3C2412_IISMOD_MODE_MASK) { + case S3C2412_IISMOD_MODE_TXRX: + case S3C2412_IISMOD_MODE_RXONLY: + /* do nothing, we are in the right mode */ + break; + + case S3C2412_IISMOD_MODE_TXONLY: + mod &= ~S3C2412_IISMOD_MODE_MASK; + mod |= S3C2412_IISMOD_MODE_TXRX; + break; + + default: + dev_err(i2s->dev, "RXEN: Invalid MODE %x in IISMOD\n", + mod & S3C2412_IISMOD_MODE_MASK); + } + + writel(mod, regs + S3C2412_IISMOD); + writel(con, regs + S3C2412_IISCON); + } else { + /* See txctrl notes on FIFOs. */ + + con &= ~S3C2412_IISCON_RXDMA_ACTIVE; + con |= S3C2412_IISCON_RXDMA_PAUSE; + con |= S3C2412_IISCON_RXCH_PAUSE; + + switch (mod & S3C2412_IISMOD_MODE_MASK) { + case S3C2412_IISMOD_MODE_RXONLY: + con &= ~S3C2412_IISCON_IIS_ACTIVE; + mod &= ~S3C2412_IISMOD_MODE_MASK; + break; + + case S3C2412_IISMOD_MODE_TXRX: + mod &= ~S3C2412_IISMOD_MODE_MASK; + mod |= S3C2412_IISMOD_MODE_TXONLY; + break; + + default: + dev_err(i2s->dev, "RXDIS: Invalid MODE %x in IISMOD\n", + mod & S3C2412_IISMOD_MODE_MASK); + } + + writel(con, regs + S3C2412_IISCON); + writel(mod, regs + S3C2412_IISMOD); + } + + fic = readl(regs + S3C2412_IISFIC); + pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); +} + +/* + * Wait for the LR signal to allow synchronisation to the L/R clock + * from the codec. May only be needed for slave mode. + */ +static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s) +{ + u32 iiscon; + unsigned long loops = msecs_to_loops(5); + + pr_debug("Entered %s\n", __func__); + + while (--loops) { + iiscon = readl(i2s->regs + S3C2412_IISCON); + if (iiscon & S3C2412_IISCON_LRINDEX) + break; + + cpu_relax(); + } + + if (!loops) { + printk(KERN_ERR "%s: timeout\n", __func__); + return -ETIMEDOUT; + } + + return 0; +} + +static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct s3c_i2sv2_info *i2s = to_info(dai); + int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); + unsigned long irqs; + int ret = 0; + + pr_debug("Entered %s\n", __func__); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (!i2s->master) { + ret = s3c2412_snd_lrsync(i2s); + if (ret) + goto exit_err; + } + + local_irq_save(irqs); + + if (capture) + s3c2412_snd_rxctrl(i2s, 1); + else + s3c2412_snd_txctrl(i2s, 1); + + local_irq_restore(irqs); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + local_irq_save(irqs); + + if (capture) + s3c2412_snd_rxctrl(i2s, 0); + else + s3c2412_snd_txctrl(i2s, 0); + + local_irq_restore(irqs); + break; + default: + ret = -EINVAL; + break; + } + +exit_err: + return ret; +} + static int s5p_i2s_wr_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -510,7 +840,7 @@ static void s5p_i2s_wr_shutdown(struct snd_pcm_substream *substream, (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S24_LE) -static void s3c64xx_iis_dai_init(struct snd_soc_dai *dai) +static void s3c64xx_iis_dai_init(struct snd_soc_dai_driver *dai) { dai->name = "s5pc1xx-i2s"; dai->playback.channels_min = 2; @@ -581,7 +911,7 @@ static int s5p_i2s_resume(struct snd_soc_dai *dai) #define s3c2412_i2s_resume NULL #endif /* CONFIG_PM */ -int s5p_i2sv5_register_dai(struct snd_soc_dai *dai) +int s5p_i2sv5_register_dai(struct device *dev, struct snd_soc_dai_driver *dai) { struct snd_soc_dai_ops *ops = dai->ops; @@ -595,14 +925,14 @@ int s5p_i2sv5_register_dai(struct snd_soc_dai *dai) /* suspend/resume are not necessary due to Clock/Pwer gating scheme */ dai->suspend = s5p_i2s_suspend; dai->resume = s5p_i2s_resume; - return snd_soc_register_dai(dai); + return snd_soc_register_dai(dev, dai); } static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev) { struct s3c_audio_pdata *i2s_pdata; struct s3c_i2sv2_info *i2s; - struct snd_soc_dai *dai; + struct snd_soc_dai_driver *dai; struct resource *res; struct clk *fout_epll, *mout_epll; struct clk *mout_audss = NULL; @@ -616,8 +946,8 @@ static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev) i2s = &s3c64xx_i2s[pdev->id]; i2s->dev = &pdev->dev; - dai = &s3c64xx_i2s_dai[pdev->id]; - dai->dev = &pdev->dev; + dai = &s3c64xx_i2s_dai_driver[pdev->id]; + //dai->dev = &pdev->dev; dai->id = pdev->id; s3c64xx_iis_dai_init(dai); @@ -660,7 +990,8 @@ static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev) i2s_pdata = pdev->dev.platform_data; - dai->private_data = i2s; + //dai->private_data = i2s; + dev_set_drvdata(&pdev->dev, i2s); base = i2s->dma_playback->dma_addr - S3C2412_IISTXD; i2s->regs = ioremap(base, 0x100); @@ -760,7 +1091,7 @@ static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev) s5p_i2s_sec_init(i2s->regs, base); #endif - ret = s5p_i2sv5_register_dai(dai); + ret = s5p_i2sv5_register_dai(&pdev->dev, dai); if (ret != 0) goto err_i2sv5; @@ -798,7 +1129,7 @@ static struct platform_driver s3c64xx_iis_driver = { .probe = s3c64xx_iis_dev_probe, .remove = s3c64xx_iis_dev_remove, .driver = { - .name = "s5pc1xx-iis", + .name = "samsung-i2s", .owner = THIS_MODULE, }, }; diff --git a/sound/soc/samsung/s5pc1xx-i2s.h b/sound/soc/samsung/s5pc1xx-i2s.h index 8d36fb3..b754cd5 100644 --- a/sound/soc/samsung/s5pc1xx-i2s.h +++ b/sound/soc/samsung/s5pc1xx-i2s.h @@ -17,7 +17,84 @@ struct clk; -#include "s3c-i2s-v2.h" +//#include "s3c-i2s-v2.h" +//== + +#define S3C_I2SV2_DIV_BCLK (1) +#define S3C_I2SV2_DIV_RCLK (2) +#define S3C_I2SV2_DIV_PRESCALER (3) + +/** + * struct s3c_i2sv2_info - S3C I2S-V2 information + * @dev: The parent device passed to use from the probe. + * @regs: The pointer to the device registe block. + * @master: True if the I2S core is the I2S bit clock master. + * @dma_playback: DMA information for playback channel. + * @dma_capture: DMA information for capture channel. + * @suspend_iismod: PM save for the IISMOD register. + * @suspend_iiscon: PM save for the IISCON register. + * @suspend_iispsr: PM save for the IISPSR register. + * + * This is the private codec state for the hardware associated with an + * I2S channel such as the register mappings and clock sources. + */ +struct s3c_i2sv2_info { + struct device *dev; + void __iomem *regs; + + struct clk *sclk_audio; + struct clk *iis_ipclk; + struct clk *iis_cclk; + struct clk *iis_clk; + struct clk *iis_busclk; + struct regulator *regulator; + + unsigned char master; + + struct s3c_dma_params *dma_playback; + struct s3c_dma_params *dma_capture; + + u32 suspend_iismod; + u32 suspend_iiscon; + u32 suspend_iispsr; + u32 suspend_iisahb; + u32 suspend_audss_clksrc; + u32 suspend_audss_clkdiv; + u32 suspend_audss_clkgate; +}; + +struct s3c_i2sv2_rate_calc { + unsigned int clk_div; /* for prescaler */ + unsigned int fs_div; /* for root frame clock */ +}; + +extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, + unsigned int *fstab, + unsigned int rate, struct clk *clk); + +/** + * s3c_i2sv2_probe - probe for i2s device helper + * @pdev: The platform device supplied to the original probe. + * @dai: The ASoC DAI structure supplied to the original probe. + * @i2s: Our local i2s structure to fill in. + * @base: The base address for the registers. + */ +extern int s3c_i2sv2_probe(struct platform_device *pdev, + struct snd_soc_dai *dai, + struct s3c_i2sv2_info *i2s, + unsigned long base); + +/** + * s3c_i2sv2_register_dai - register dai with soc core + * @dai: The snd_soc_dai structure to register + * + * Fill in any missing fields and then register the given dai with the + * soc core. + */ +extern int s3c_i2sv2_register_dai(struct snd_soc_dai *dai); +extern void s5p_idma_init(void *); + +//== #define USE_CLKAUDIO 1 @@ -42,12 +119,6 @@ extern int s5p_i2s_hw_params(struct snd_pcm_substream *substream, extern int s5p_i2s_startup(struct snd_soc_dai *dai); extern int s5p_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai); -extern int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai); -extern int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai); - extern void s5p_i2s_sec_init(void *, dma_addr_t); #endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */ |