diff options
author | Arve Hjønnevåg <arve@android.com> | 2011-04-15 21:14:05 -0700 |
---|---|---|
committer | Arve Hjønnevåg <arve@android.com> | 2011-11-17 17:54:05 -0800 |
commit | 01a869655432e964c1651c85a465b463db175286 (patch) | |
tree | 4f7e81a801ccd4f1931237981d226a729e0e53e6 | |
parent | d6b5d265382e39d707525839fa5fe2c06a28892e (diff) | |
download | kernel_samsung_crespo-01a869655432e964c1651c85a465b463db175286.zip kernel_samsung_crespo-01a869655432e964c1651c85a465b463db175286.tar.gz kernel_samsung_crespo-01a869655432e964c1651c85a465b463db175286.tar.bz2 |
ARM: herring: sound: Use audio driver from 2.6.35
fix herring-wm8994.c to compile on 2.6.39
checkpoint: use mainline sound driver
checkout: audio driver loads but locks up
checkpoint: audio setup does not complain, but playback times-out
checkpoint: using soc sound i2s and dma code from 2.6.35 - dma still hangs
checkpoint: using old codec, dma and i2s code sound plays but is distorded
fix distorted sound
rename samsung wm8994 codec to not conflict with standard wm8994 mfd device
modify dma.c to work with dma wrapper
rename some audio config options and fix defconfig
remove some duplicate clocks
Change-Id: I1b72b5b7937fd4a40a1719674976ba16d7e8f3a6
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 */ |