#include <sound/pcm_params.h>
#include <sound/tlv.h>
#include <sound/soc.h>
+#include <sound/soc-dapm.h>
#include <sound/initval.h>
+#include <mach/iomux.h>
+#include <mach/gpio.h>
+
#include "wm8988.h"
+#include <linux/proc_fs.h>
+#include <linux/gpio.h>
+
+#if 0
+#define DBG(x...) printk(KERN_INFO x)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
/*
* wm8988 register cache
* We can't read the WM8988 register space when we
unsigned int sysclk;
enum snd_soc_control_type control_type;
struct snd_pcm_hw_constraint_list *sysclk_constraints;
+ int is_startup; // gModify.Add
+ int is_biason;
};
else
adctl2 |= 0x4;
+ DBG("Enter::%s----%d, adctl2 = %x\n",__FUNCTION__,__LINE__,adctl2);
+
return snd_soc_write(codec, WM8988_ADCTL2, adctl2);
}
SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8988_PWR1, 2, 0),
SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8988_PWR1, 3, 0),
- SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8988_PWR2, 7, 0),
- SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8988_PWR2, 8, 0),
+ /* gModify.Cmmt Implement when suspend/startup */
+ /*SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8988_PWR2, 7, 0),*/
+ /*SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8988_PWR2, 8, 0),*/
SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
&wm8988_left_mixer_controls[0],
};
static unsigned int rates_12[] = {
- 8000, 11025, 12000, 16000, 22050, 2400, 32000, 41100, 48000,
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
48000, 88235, 96000,
};
struct snd_soc_codec *codec = codec_dai->codec;
struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
switch (freq) {
case 11289600:
case 18432000:
return -EINVAL;
}
+ DBG("Enter::%s----%d iface=%x\n",__FUNCTION__,__LINE__,iface);
+
snd_soc_write(codec, WM8988_IFACE, iface);
return 0;
}
struct snd_soc_codec *codec = dai->codec;
struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
+ if (!wm8988->is_startup) {
+ wm8988->is_startup = 1;
+ snd_soc_write(codec, WM8988_PWR1, 0xfc);
+ gpio_direction_output(RK29_PIN6_PB5, GPIO_LOW);
+ mdelay(100); // Discharge C310
+ snd_soc_write(codec, WM8988_PWR2, 0x1e0);
+ gpio_direction_output(RK29_PIN6_PB5, GPIO_HIGH);
+ }
+
+ DBG("Enter::%s----%d wm8988->sysclk=%d\n",__FUNCTION__,__LINE__,wm8988->sysclk);
+
/* The set of sample rates that can be supported depends on the
* MCLK supplied to the CODEC - enforce this.
*/
break;
}
+ DBG("Enter::%s----%d iface=%x srate =%x rate=%d\n",__FUNCTION__,__LINE__,iface,srate,params_rate(params));
+
/* set iface & srate */
snd_soc_write(codec, WM8988_IFACE, iface);
if (coeff >= 0)
struct snd_soc_codec *codec = dai->codec;
u16 mute_reg = snd_soc_read(codec, WM8988_ADCDAC) & 0xfff7;
+ DBG("Enter::%s----%d--mute=%d\n",__FUNCTION__,__LINE__,mute);
+
if (mute)
snd_soc_write(codec, WM8988_ADCDAC, mute_reg | 0x8);
else
static int wm8988_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
u16 pwr_reg = snd_soc_read(codec, WM8988_PWR1) & ~0x1c1;
+ DBG("Enter::%s----%d level =%d\n",__FUNCTION__,__LINE__,level);
+
switch (level) {
case SND_SOC_BIAS_ON:
+ wm8988->is_biason = 1;
break;
case SND_SOC_BIAS_PREPARE:
+ if (wm8988->is_startup && wm8988->is_biason) {
+ snd_soc_write(codec, WM8988_PWR2, 0x0);
+ wm8988->is_startup = 0;
+ wm8988->is_biason = 0;
+ }
/* VREF, VMID=2x50k, digital enabled */
snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x00c0);
break;
};
static struct snd_soc_dai_driver wm8988_dai = {
- .name = "wm8988-hifi",
+ .name = "WM8988 HiFi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
static int wm8988_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
u8 data[2];
u16 *cache = codec->reg_cache;
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
/* Sync reg_cache with the hardware */
for (i = 0; i < WM8988_NUM_REG; i++) {
if (i == WM8988_RESET)
data[1] = cache[i] & 0x00ff;
codec->hw_write(codec->control_data, data, 2);
}
+
+ //snd_soc_write(codec, WM8988_PWR1, 0xfc);
+ //snd_soc_write(codec, WM8988_PWR2, 0x1e0);
wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
+static struct snd_soc_codec *wm8988_codec;
+
+static int entry_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ snd_soc_write(wm8988_codec, WM8988_PWR1, 0x0000);
+ snd_soc_write(wm8988_codec, WM8988_PWR2, 0x0000);
+
+ len = sprintf(page, "wm8988 suspend...\n");
+
+ return len ;
+}
+
static int wm8988_probe(struct snd_soc_codec *codec)
{
struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
u16 reg;
+ if (codec == NULL) {
+ dev_err(codec->dev, "Codec device not registered\n");
+ return -ENODEV;
+ }
+
+ wm8988_codec = codec;
+
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8988->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
+#if 0
+ /*disable speaker */
+ gpio_request(RK2818_PIN_PF7, "WM8988");
+ rk2818_mux_api_set(GPIOE_SPI1_FLASH_SEL_NAME, IOMUXA_GPIO1_A3B7);
+ gpio_direction_output(RK2818_PIN_PF7,GPIO_HIGH);
+
+#endif
+
/* set the update bits (we always update left then right) */
reg = snd_soc_read(codec, WM8988_RADC);
snd_soc_write(codec, WM8988_RADC, reg | 0x100);
reg = snd_soc_read(codec, WM8988_ROUT2V);
snd_soc_write(codec, WM8988_ROUT2V, reg | 0x0100);
reg = snd_soc_read(codec, WM8988_RINVOL);
- snd_soc_write(codec, WM8988_RINVOL, reg | 0x0100);
+ snd_soc_write(codec, WM8988_RINVOL, reg | 0x0100);
+
+ snd_soc_write(codec, WM8988_LOUTM1, 0x120);
+ snd_soc_write(codec, WM8988_ROUTM2, 0x120);
+ snd_soc_write(codec, WM8988_LOUTM2, 0x0070);
+ snd_soc_write(codec, WM8988_ROUTM1, 0x0070);
+//tcl miaozh modify
+// snd_soc_write(codec, WM8988_LOUT1V, 0x017f);
+// snd_soc_write(codec, WM8988_ROUT1V, 0x017f);
+ snd_soc_write(codec, WM8988_LOUT1V, 0x017a);
+ snd_soc_write(codec, WM8988_ROUT1V, 0x017a);
+
+ snd_soc_write(codec, WM8988_LDAC, 0xfa/*0xff*/); // Change max by zhansb@110415
+ snd_soc_write(codec, WM8988_RDAC, 0x1fa/*0x1ff*/);//vol set
+
+ //TCL lgw add 20110412
+ snd_soc_write(codec, WM8988_LINVOL, 0x0117);
+ snd_soc_write(codec, WM8988_RINVOL, 0x0117);
+
+ snd_soc_write(codec, WM8988_ADCTL2, 0x0184);
+
+ snd_soc_write(codec, WM8988_LADC, 0x01ec);
+ snd_soc_write(codec, WM8988_RADC, 0x01ec);
+
+ snd_soc_write(codec, WM8988_ADCIN, 0x0140);
+ snd_soc_write(codec, WM8988_LADCIN, 0x00f0);//0x00e0
+ snd_soc_write(codec, WM8988_RADCIN, 0x0);//0x00e0
+ //lgw end
+
+ snd_soc_write(codec, WM8988_SRATE,0x100); ///SET MCLK/8
+ //snd_soc_write(codec, WM8988_PWR1, 0x1cc); ///(0x80|0x40|0x20|0x08|0x04|0x10|0x02));
+ //TCL lgw modify 20110412
+ //snd_soc_write(codec, WM8988_PWR1, 0xfc);
+ //snd_soc_write(codec, WM8988_PWR2, 0x1e0); //power r l out1
wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
snd_soc_dapm_new_controls(dapm, wm8988_dapm_widgets,
ARRAY_SIZE(wm8988_dapm_widgets));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+ create_proc_read_entry("wm8988_suspend", 0644, NULL, entry_read, NULL);
return 0;
}
static struct spi_driver wm8988_spi_driver = {
.driver = {
- .name = "wm8988-codec",
+ .name = "WM8988",
.owner = THIS_MODULE,
},
.probe = wm8988_spi_probe,
static struct i2c_driver wm8988_i2c_driver = {
.driver = {
- .name = "wm8988-codec",
+ .name = "WM8988",
.owner = THIS_MODULE,
},
.probe = wm8988_i2c_probe,
/*
- * rk2818_wm8988.c -- SoC audio for rockchip
+ * rk29_wm8988.c -- SoC audio for rockchip
*
* Driver for rockchip wm8988 audio
*
#include "rk29_pcm.h"
#include "rk29_i2s.h"
+#include <mach/gpio.h>
+
#if 0
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
-static int rk2818_hw_params(struct snd_pcm_substream *substream,
+//static void *rk29_speaker = NULL;
+
+static int rk29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
#define HW_PARAMS_FLAG_EQVOL_OFF 0x22
if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
{
- ret = codec_dai->ops->hw_params(substream, params, codec_dai); //by Vincent
+ ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); //by Vincent
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
}
else
{
/* set codec DAI configuration */
- #if defined (CONFIG_SND_CODEC_SOC_SLAVE)
- ret = codec_dai->ops->set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
#endif
- #if defined (CONFIG_SND_CODEC_SOC_MASTER)
- ret = codec_dai->ops->set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM );
#endif
if (ret < 0)
return ret;
/* set cpu DAI configuration */
- #if defined (CONFIG_SND_CODEC_SOC_SLAVE)
- ret = cpu_dai->ops->set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
#endif
- #if defined (CONFIG_SND_CODEC_SOC_MASTER)
- ret = cpu_dai->ops->set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
#endif
if (ret < 0)
return ret;
}
-
+
return 0;
}
-static const struct snd_soc_dapm_widget rk2818_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget rk29_dapm_widgets[] = {
SND_SOC_DAPM_LINE("Audio Out", NULL),
SND_SOC_DAPM_LINE("Line in", NULL),
SND_SOC_DAPM_MIC("Micn", NULL),
/*
* Logic for a wm8988 as connected on a rockchip board.
*/
-static int rk2818_wm8988_init(struct snd_soc_codec *codec)
+static int rk29_wm8988_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *codec_dai = &codec->dai[0];
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
ret = snd_soc_dai_set_sysclk(codec_dai, 0,
- 12000000, SND_SOC_CLOCK_IN);
+ /*12000000*/11289600, SND_SOC_CLOCK_IN);
if (ret < 0) {
printk(KERN_ERR "Failed to set WM8988 SYSCLK: %d\n", ret);
return ret;
}
/* Add specific widgets */
- snd_soc_dapm_new_controls(codec, rk2818_dapm_widgets,
- ARRAY_SIZE(rk2818_dapm_widgets));
- snd_soc_dapm_nc_pin(codec, "LOUT2");
- snd_soc_dapm_nc_pin(codec, "ROUT2");
+ snd_soc_dapm_new_controls(dapm, rk29_dapm_widgets,
+ ARRAY_SIZE(rk29_dapm_widgets));
+ //snd_soc_dapm_nc_pin(codec, "LOUT2");
+ //snd_soc_dapm_nc_pin(codec, "ROUT2");
/* Set up specific audio path audio_mapnects */
- snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+ snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
- snd_soc_dapm_sync(codec);
+ snd_soc_dapm_sync(dapm);
return 0;
}
-static struct snd_soc_ops rk2818_ops = {
- .hw_params = rk2818_hw_params,
+static struct snd_soc_ops rk29_ops = {
+ .hw_params = rk29_hw_params,
};
-static struct snd_soc_dai_link rk2818_dai = {
- .name = "WM8988",
- .stream_name = "WM8988 PCM",
- .cpu_dai = &rk2818_i2s_dai,
- .codec_dai = &wm8988_dai,
- .init = rk2818_wm8988_init,
- .ops = &rk2818_ops,
+static struct snd_soc_dai_link rk29_dai = {
+ .name = "WM8988",
+ .stream_name = "WM8988 PCM",
+ .codec_name = "WM8988.0-001a",
+ .platform_name = "rockchip-audio",
+ .cpu_dai_name = "rk29_i2s.0",
+ .codec_dai_name = "WM8988 HiFi",
+ .init = rk29_wm8988_init,
+ .ops = &rk29_ops,
};
-static struct snd_soc_card snd_soc_card_rk2818 = {
- .name = "RK2818_WM8988",
- .platform = &rk2818_soc_platform,
- .dai_link = &rk2818_dai,
- .num_links = 1,
+static struct snd_soc_card snd_soc_card_rk29 = {
+ .name = "RK29_WM8988",
+ .dai_link = &rk29_dai,
+ .num_links = 1,
};
-
-static struct snd_soc_device rk2818_snd_devdata = {
- .card = &snd_soc_card_rk2818,
- .codec_dev = &soc_codec_dev_wm8988,
-};
-
-static struct platform_device *rk2818_snd_device;
+static struct platform_device *rk29_snd_device;
static int __init audio_card_init(void)
{
- int ret =0;
+ int ret =0;
+
+ //rk29_speaker = rk29_speaker_init(RK29_PIN6_PB6, GPIO_HIGH, 2, (200*1000*1000));
+
DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
- rk2818_snd_device = platform_device_alloc("soc-audio", -1);
- if (!rk2818_snd_device) {
+ rk29_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!rk29_snd_device) {
DBG("platform device allocation failed\n");
ret = -ENOMEM;
return ret;
}
- platform_set_drvdata(rk2818_snd_device, &rk2818_snd_devdata);
- rk2818_snd_devdata.dev = &rk2818_snd_device->dev;
- ret = platform_device_add(rk2818_snd_device);
+ platform_set_drvdata(rk29_snd_device, &snd_soc_card_rk29);
+ ret = platform_device_add(rk29_snd_device);
if (ret) {
DBG("platform device add failed\n");
- platform_device_put(rk2818_snd_device);
+ platform_device_put(rk29_snd_device);
+ return ret;
}
- return ret;
+
+ return ret;
}
static void __exit audio_card_exit(void)
{
- platform_device_unregister(rk2818_snd_device);
+ platform_device_unregister(rk29_snd_device);
+ //rk29_speaker_deinit(rk29_speaker);
}
module_init(audio_card_init);