Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
- index 7d5a661..4b94603 100644
- --- a/sound/soc/codecs/Kconfig
- +++ b/sound/soc/codecs/Kconfig
- @@ -41,6 +41,7 @@ config SND_SOC_ALL_CODECS
- select SND_SOC_PCM3008
- select SND_SOC_RT5639 if I2C
- select SND_SOC_RT5640 if I2C
- + select SND_SOC_RT5642 if I2C
- select SND_SOC_SGTL5000 if I2C
- select SND_SOC_SN95031 if INTEL_SCU_IPC
- select SND_SOC_SPDIF
- @@ -223,6 +224,8 @@ config SND_SOC_RT5639
- config SND_SOC_RT5640
- tristate
- +config SND_SOC_RT5642
- + tristate
- #Freescale sgtl5000 codec
- config SND_SOC_SGTL5000
- tristate
- diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
- index 2eaef5b..8eb8bfe 100644
- --- a/sound/soc/codecs/Makefile
- +++ b/sound/soc/codecs/Makefile
- @@ -90,6 +90,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o
- snd-soc-jz4740-codec-objs := jz4740.o
- snd-soc-rt5639-objs := rt5639.o
- snd-soc-rt5640-objs := rt5640.o
- +snd-soc-rt5640-dsp-objs := rt5640-dsp.o
- # Amp
- snd-soc-lm4857-objs := lm4857.o
- @@ -189,6 +190,7 @@ obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
- obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
- obj-$(CONFIG_SND_SOC_RT5639) += snd-soc-rt5639.o
- obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
- +obj-$(CONFIG_SND_SOC_RT5642) += snd-soc-rt5640-dsp.o
- # Amp
- obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o
- diff --git a/sound/soc/codecs/rt5639.c b/sound/soc/codecs/rt5639.c
- index 139503e..06c8451 100644
- --- a/sound/soc/codecs/rt5639.c
- +++ b/sound/soc/codecs/rt5639.c
- @@ -2239,6 +2239,8 @@ static int rt5639_probe(struct snd_soc_codec *codec)
- struct rt5639_priv *rt5639 = snd_soc_codec_get_drvdata(codec);
- int ret;
- + codec->dapm.idle_bias_off = 1;
- +
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- diff --git a/sound/soc/codecs/rt5640-dsp.c b/sound/soc/codecs/rt5640-dsp.c
- new file mode 100644
- index 0000000..e00fec5
- --- /dev/null
- +++ b/sound/soc/codecs/rt5640-dsp.c
- @@ -0,0 +1,1359 @@
- +/*
- + * rt5640.c -- RT5640 ALSA SoC DSP driver
- + *
- + * Copyright 2011 Realtek Semiconductor Corp.
- + * Author: Johnny Hsu <johnnyhsu@realtek.com>
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License version 2 as
- + * published by the Free Software Foundation.
- + */
- +
- +#include <linux/delay.h>
- +#include <linux/i2c.h>
- +#include <linux/platform_device.h>
- +#include <sound/soc.h>
- +#include <sound/soc-dapm.h>
- +
- +#define RTK_IOCTL
- +#ifdef RTK_IOCTL
- +#include <linux/spi/spi.h> //kmalloc kfree
- +
- +#include "rt56xx_ioctl.h"
- +#define DBG 1
- +#endif
- +
- +#include "rt5640.h"
- +#include "rt5640-dsp.h"
- +
- +
- +static const u16 rt5640_dsp_init[][2] = {
- + {0x3fd2, 0x0038}, {0x229C, 0x0fa0}, {0x22d2, 0x8400}, {0x22ee, 0x0001},
- + {0x22f2, 0x0040}, {0x22f5, 0x8000}, {0x22f6, 0x0000}, {0x22f9, 0x007f},
- + {0x2310, 0x0880},
- +};
- +#define RT5640_DSP_INIT_NUM \
- + (sizeof(rt5640_dsp_init) / sizeof(rt5640_dsp_init[0]))
- +
- +static const u16 rt5640_dsp_48[][2] = {
- + {0x22c8, 0x0026}, {0x22fe, 0x0fa0}, {0x22ff, 0x3893}, {0x22fa, 0x2487},
- + {0x2301, 0x0002},
- +};
- +#define RT5640_DSP_48_NUM (sizeof(rt5640_dsp_48) / sizeof(rt5640_dsp_48[0]))
- +
- +static const u16 rt5640_dsp_441[][2] = {
- + {0x22c6, 0x0031}, {0x22c7, 0x0050}, {0x22c8, 0x0009}, {0x22fe, 0x0e5b},
- + {0x22ff, 0x3c83}, {0x22fa, 0x2484}, {0x2301, 0x0001},
- +};
- +#define RT5640_DSP_441_NUM (sizeof(rt5640_dsp_441) / sizeof(rt5640_dsp_441[0]))
- +
- +static const u16 rt5640_dsp_16[][2] = {
- + {0x22c8, 0x0026}, {0x22fa, 0x2484}, {0x2301, 0x0002},
- +};
- +#define RT5640_DSP_16_NUM (sizeof(rt5640_dsp_16) / sizeof(rt5640_dsp_16[0]))
- +
- +static const u16 rt5640_dsp_aec_ns_fens[][2] = {
- + {0x22f8, 0x8005}, {0x2303, 0x0971}, {0x2304, 0x0312}, {0x2305, 0x0005},
- + {0x2309, 0x0400}, {0x230a, 0x1b00}, {0x230c, 0x0200}, {0x230d, 0x0400},
- + {0x2310, 0x0824}, {0x2325, 0x5000}, {0x2326, 0x0040}, {0x232f, 0x0080},
- + {0x2332, 0x0080}, {0x2333, 0x0008}, {0x2337, 0x0002}, {0x2339, 0x0010},
- + {0x2348, 0x1000}, {0x2349, 0x1000}, {0x2360, 0x0180}, {0x2361, 0x1800},
- + {0x2362, 0x0180}, {0x2363, 0x0100}, {0x2364, 0x0078}, {0x2365, 0x2000},
- + {0x236e, 0x1800}, {0x236f, 0x0a0a}, {0x2370, 0x0f00}, {0x2372, 0x1a00},
- + {0x2373, 0x3000}, {0x2374, 0x2400}, {0x2375, 0x1800}, {0x2380, 0x7fff},
- + {0x2381, 0x4000}, {0x2382, 0x0400}, {0x2383, 0x0400}, {0x2384, 0x0005},
- + {0x2385, 0x0005}, {0x238c, 0x0400}, {0x238e, 0x7000}, {0x2393, 0x4444},
- + {0x2394, 0x4444}, {0x2395, 0x4444}, {0x2396, 0x2000}, {0x2396, 0x3000},
- + {0x2398, 0x0020}, {0x23a5, 0x0006}, {0x23a6, 0x7fff}, {0x23b3, 0x000e},
- + {0x23b4, 0x000a}, {0x23b7, 0x0008}, {0x23bb, 0x1000}, {0x23bc, 0x0130},
- + {0x23bd, 0x0100}, {0x23be, 0x2400}, {0x23cf, 0x0800}, {0x23d0, 0x0400},
- + {0x23d1, 0xff80}, {0x23d2, 0xff80}, {0x23d3, 0x0800}, {0x23d4, 0x3e00},
- + {0x23d5, 0x5000}, {0x23e7, 0x0800}, {0x23e8, 0x0e00}, {0x23e9, 0x7000},
- + {0x23ea, 0x7ff0}, {0x23ed, 0x0300}, {0x22fb, 0x0000},
- +};
- +#define RT5640_DSP_AEC_NUM \
- + (sizeof(rt5640_dsp_aec_ns_fens) / sizeof(rt5640_dsp_aec_ns_fens[0]))
- +
- +static const u16 rt5640_dsp_hfbf[][2] = {
- + {0x22f8, 0x8004}, {0x22a0, 0x1205}, {0x22a1, 0x0f00}, {0x22a2, 0x1000},
- + {0x22a3, 0x1000}, {0x22a4, 0x1000}, {0x22aa, 0x0006}, {0x22ad, 0x0060},
- + {0x22ae, 0x0080}, {0x22af, 0x0000}, {0x22b0, 0x000e}, {0x22b1, 0x0010},
- + {0x22b2, 0x0006}, {0x22b3, 0x0001}, {0x22b4, 0x0010}, {0x22b5, 0x0001},
- + {0x22b7, 0x0005}, {0x22d8, 0x0017}, {0x22f9, 0x007f}, {0x2303, 0x0971},
- + {0x2304, 0x0302}, {0x2303, 0x0971}, {0x2304, 0x4302}, {0x2305, 0x102d},
- + {0x2309, 0x0400}, {0x230c, 0x0400}, {0x230d, 0x0200}, {0x232f, 0x0020},
- + {0x2332, 0x0100}, {0x2333, 0x0020}, {0x2337, 0xffff}, {0x2339, 0x0010},
- + {0x2348, 0x1000}, {0x2349, 0x1000}, {0x236e, 0x1800}, {0x236f, 0x1006},
- + {0x2370, 0x1000}, {0x2372, 0x0200}, {0x237b, 0x001e}, {0x2380, 0x7fff},
- + {0x2381, 0x4000}, {0x2382, 0x0080}, {0x2383, 0x0200}, {0x2386, 0x7f80},
- + {0x2387, 0x0040}, {0x238a, 0x0280}, {0x238c, 0x6000}, {0x238e, 0x5000},
- + {0x2396, 0x6a00}, {0x2397, 0x6000}, {0x2398, 0x00e0}, {0x23a5, 0x0005},
- + {0x23b3, 0x000f}, {0x23b4, 0x0003}, {0x23bb, 0x2000}, {0x23bc, 0x00d0},
- + {0x23bd, 0x0140}, {0x23be, 0x1000}, {0x23cf, 0x0800}, {0x23d0, 0x0400},
- + {0x23d1, 0x0100}, {0x23d2, 0x0100}, {0x23d5, 0x7c00}, {0x23ed, 0x0300},
- + {0x23ee, 0x3000}, {0x23ef, 0x2800}, {0x22fb, 0x0000},
- +};
- +#define RT5640_DSP_HFBF_NUM \
- + (sizeof(rt5640_dsp_hfbf) / sizeof(rt5640_dsp_hfbf[0]))
- +
- +static const u16 rt5640_dsp_ffp[][2] = {
- + {0x22f8, 0x8005}, {0x2303, 0x1971}, {0x2304, 0x8312}, {0x2305, 0x0005},
- + {0x2309, 0x0200}, {0x230a, 0x1b00}, {0x230c, 0x0800}, {0x230d, 0x0400},
- + {0x2325, 0x5000}, {0x2326, 0x0040}, {0x232f, 0x0080}, {0x2332, 0x0100},
- + {0x2333, 0x0020}, {0x2337, 0x0001}, {0x2339, 0x0010}, {0x233c, 0x0040},
- + {0x2348, 0x1000}, {0x2349, 0x1000}, {0x2360, 0x0180}, {0x2361, 0x1800},
- + {0x2362, 0x0200}, {0x2363, 0x0200}, {0x2364, 0x0200}, {0x2365, 0x2000},
- + {0x236e, 0x1000}, {0x236f, 0x0a05}, {0x2370, 0x0f00}, {0x2372, 0x1a00},
- + {0x2373, 0x3000}, {0x2374, 0x2400}, {0x2375, 0x1800}, {0x2380, 0x7fff},
- + {0x2381, 0x4000}, {0x2382, 0x0400}, {0x2383, 0x0400}, {0x2384, 0x0005},
- + {0x2385, 0x0005}, {0x238e, 0x7000}, {0x2393, 0x4444}, {0x2394, 0x4444},
- + {0x2395, 0x4444}, {0x2396, 0x2000}, {0x2397, 0x3000}, {0x2398, 0x0020},
- + {0x23a5, 0x0006}, {0x23a6, 0x7fff}, {0x23b3, 0x000a}, {0x23b4, 0x0006},
- + {0x23b7, 0x0008}, {0x23bb, 0x1000}, {0x23bc, 0x0130}, {0x23bd, 0x0160},
- + {0x23be, 0x2400}, {0x23cf, 0x0800}, {0x23d0, 0x0400}, {0x23d1, 0xff80},
- + {0x23d2, 0xff80}, {0x23d3, 0x2000}, {0x23d4, 0x5000}, {0x23d5, 0x5000},
- + {0x23e7, 0x0c00}, {0x23e8, 0x1400}, {0x23e9, 0x6000}, {0x23ea, 0x7f00},
- + {0x23ed, 0x0300}, {0x23ee, 0x2800}, {0x22fb, 0x0000},
- +};
- +#define RT5640_DSP_FFP_NUM (sizeof(rt5640_dsp_ffp) / sizeof(rt5640_dsp_ffp[0]))
- +
- +static const u16 rt5640_dsp_p3_tab[][3] = {
- + {0x4af0, 0x1000, 0x822b}, {0x90f0, 0x1001, 0x8393},
- + {0x64f0, 0x1002, 0x822b}, {0x0ff0, 0x1003, 0x26e0},
- + {0x55f0, 0x1004, 0x2200}, {0xcff0, 0x1005, 0x1a7b},
- + {0x5af0, 0x1006, 0x823a}, {0x90f0, 0x1007, 0x8393},
- + {0x64f0, 0x1008, 0x822b}, {0x0ff0, 0x1009, 0x26e0},
- + {0x03f0, 0x100a, 0x2218}, {0x0ef0, 0x100b, 0x3400},
- + {0x4ff0, 0x100c, 0x195e}, {0x00f0, 0x100d, 0x0000},
- + {0xf0f0, 0x100e, 0x8143}, {0x1ff0, 0x100f, 0x2788},
- + {0x0ef0, 0x1010, 0x3400}, {0xe0f0, 0x1011, 0x1a26},
- + {0x2cf0, 0x1012, 0x8001}, {0x0ff0, 0x1013, 0x267c},
- + {0x82f0, 0x1014, 0x1a27}, {0x3cf0, 0x1015, 0x8001},
- + {0x0ff0, 0x1016, 0x267c}, {0x82f0, 0x1017, 0x1a27},
- + {0xeff0, 0x1018, 0x1a26}, {0x01f0, 0x1019, 0x4ff0},
- + {0x5cf0, 0x101a, 0x2b81}, {0xfaf0, 0x101b, 0x2a6a},
- + {0x05f0, 0x101c, 0x4011}, {0x0ff0, 0x101d, 0x278e},
- + {0x0ef0, 0x101e, 0x3400}, {0xe1f0, 0x101f, 0x1997},
- + {0x1ff0, 0x1020, 0x1997}, {0x03f0, 0x1021, 0x2279},
- + {0xb8f0, 0x1022, 0x8206}, {0xf8f0, 0x1023, 0x0f00},
- + {0xfff0, 0x1024, 0x279e}, {0x0ff0, 0x1025, 0x2272},
- + {0x0ef0, 0x1026, 0x3400}, {0x3ff0, 0x1027, 0x199a},
- + {0x0ff0, 0x1028, 0x2262}, {0x0ff0, 0x1029, 0x2272},
- + {0x0ef0, 0x102a, 0x3400}, {0xfff0, 0x102b, 0x199a},
- + {0x7ff0, 0x102c, 0x22e2}, {0x0ef0, 0x102d, 0x3400},
- + {0xfff0, 0x102e, 0x19cb}, {0xfff0, 0x102f, 0x47ff},
- + {0xb1f0, 0x1030, 0x80b1}, {0x5ff0, 0x1031, 0x2261},
- + {0x62f0, 0x1032, 0x1903}, {0x9af0, 0x1033, 0x0d00},
- + {0xcff0, 0x1034, 0x80b1}, {0x0ff0, 0x1035, 0x0e27},
- + {0x8ff0, 0x1036, 0x9229}, {0x0ef0, 0x1037, 0x3400},
- + {0xaff0, 0x1038, 0x19f5}, {0x81f0, 0x1039, 0x8229},
- + {0x0ef0, 0x103a, 0x3400}, {0xfff0, 0x103b, 0x19f6},
- + {0x5af0, 0x103c, 0x8234}, {0xeaf0, 0x103d, 0x9113},
- + {0x0ef0, 0x103e, 0x3400}, {0x7ff0, 0x103f, 0x19ea},
- + {0x8af0, 0x1040, 0x924d}, {0x08f0, 0x1041, 0x3400},
- + {0x3ff0, 0x1042, 0x1a74}, {0x00f0, 0x1043, 0x0000},
- + {0x00f0, 0x1044, 0x0000}, {0x00f0, 0x1045, 0x0c38},
- + {0x0ff0, 0x1046, 0x2618}, {0xb0f0, 0x1047, 0x8148},
- + {0x01f0, 0x1048, 0x3700}, {0x02f0, 0x1049, 0x3a70},
- + {0x03f0, 0x104a, 0x3a78}, {0x9af0, 0x104b, 0x8229},
- + {0xd6f0, 0x104c, 0x47c4}, {0x95f0, 0x104d, 0x4361},
- + {0x0ff0, 0x104e, 0x2082}, {0x76f0, 0x104f, 0x626b},
- + {0x0ff0, 0x1050, 0x208a}, {0x0ff0, 0x1051, 0x204a},
- + {0xc9f0, 0x1052, 0x7882}, {0x75f0, 0x1053, 0x626b},
- + {0x0ff0, 0x1054, 0x208a}, {0x0ff0, 0x1055, 0x204a},
- + {0xcdf0, 0x1056, 0x7882}, {0x0ff0, 0x1057, 0x2630},
- + {0x8af0, 0x1058, 0x2b30}, {0xf4f0, 0x1059, 0x1904},
- + {0x98f0, 0x105a, 0x9229}, {0x0ef0, 0x105b, 0x3400},
- + {0xeff0, 0x105c, 0x19fd}, {0xd7f0, 0x105d, 0x40cc},
- + {0x0ef0, 0x105e, 0x3400}, {0xdff0, 0x105f, 0x1a44},
- + {0x00f0, 0x1060, 0x0000}, {0xcef0, 0x1061, 0x1507},
- + {0x90f0, 0x1062, 0x1020}, {0x5ff0, 0x1063, 0x1006},
- + {0x89f0, 0x1064, 0x608f}, {0x0ff0, 0x1065, 0x0e64},
- + {0x49f0, 0x1066, 0x1044}, {0xcff0, 0x1067, 0x2b28},
- + {0x93f0, 0x1068, 0x2a62}, {0x5ff0, 0x1069, 0x266a},
- + {0x54f0, 0x106a, 0x22a8}, {0x0af0, 0x106b, 0x0f22},
- + {0xfbf0, 0x106c, 0x0f0c}, {0x5ff0, 0x106d, 0x0d00},
- + {0x90f0, 0x106e, 0x1020}, {0x4ff0, 0x106f, 0x1006},
- + {0x8df0, 0x1070, 0x6087}, {0x0ff0, 0x1071, 0x0e64},
- + {0xb9f0, 0x1072, 0x1044}, {0xcff0, 0x1073, 0x2a63},
- + {0x5ff0, 0x1074, 0x266a}, {0x54f0, 0x1075, 0x22a8},
- + {0x0af0, 0x1076, 0x0f22}, {0xfbf0, 0x1077, 0x0f0c},
- + {0x93f0, 0x1078, 0x2aef}, {0x0ff0, 0x1079, 0x227a},
- + {0xc2f0, 0x107a, 0x1907}, {0xf5f0, 0x107b, 0x0d00},
- + {0xfdf0, 0x107c, 0x7800}, {0x0ef0, 0x107d, 0x3400},
- + {0xaff0, 0x107e, 0x1899},
- +};
- +#define RT5640_DSP_PATCH3_NUM \
- + (sizeof(rt5640_dsp_p3_tab) / sizeof(rt5640_dsp_p3_tab[0]))
- +
- +static const u16 rt5640_dsp_p2_tab[][2] = {
- + {0x3fa1, 0xe7bb}, {0x3fb1, 0x5000}, {0x3fa2, 0xa26b}, {0x3fb2, 0x500e},
- + {0x3fa3, 0xa27c}, {0x3fb3, 0x2282}, {0x3fa4, 0x996e}, {0x3fb4, 0x5019},
- + {0x3fa5, 0x99a2}, {0x3fb5, 0x5021}, {0x3fa6, 0x99ae}, {0x3fb6, 0x5028},
- + {0x3fa7, 0x9cbb}, {0x3fb7, 0x502c}, {0x3fa8, 0x9900}, {0x3fb8, 0x1903},
- + {0x3fa9, 0x9f59}, {0x3fb9, 0x502f}, {0x3faa, 0x9f6e}, {0x3fba, 0x5039},
- + {0x3fab, 0x9ea2}, {0x3fbb, 0x503c}, {0x3fac, 0x9fc8}, {0x3fbc, 0x5045},
- + {0x3fad, 0xa44c}, {0x3fbd, 0x505d}, {0x3fae, 0x8983}, {0x3fbe, 0x5061},
- + {0x3faf, 0x95e3}, {0x3fbf, 0x5006}, {0x3fa0, 0xe742}, {0x3fb0, 0x5040},
- +};
- +#define RT5640_DSP_PATCH2_NUM \
- + (sizeof(rt5640_dsp_p2_tab) / sizeof(rt5640_dsp_p2_tab[0]))
- +
- +/**
- + * rt5640_dsp_done - Wait until DSP is ready.
- + * @codec: SoC Audio Codec device.
- + *
- + * To check voice DSP status and confirm it's ready for next work.
- + *
- + * Returns 0 for success or negative error code.
- + */
- +static int rt5640_dsp_done(struct snd_soc_codec *codec)
- +{
- + unsigned int count = 0, dsp_val;
- +
- + dsp_val = snd_soc_read(codec, RT5640_DSP_CTRL3);
- + while(dsp_val & RT5640_DSP_BUSY_MASK) {
- + if(count > 10)
- + return -EBUSY;
- + dsp_val = snd_soc_read(codec, RT5640_DSP_CTRL3);
- + count ++;
- + }
- +
- + return 0;
- +}
- +
- +/**
- + * rt5640_dsp_write - Write DSP register.
- + * @codec: SoC audio codec device.
- + * @param: DSP parameters.
- + *
- + * Modify voice DSP register for sound effect. The DSP can be controlled
- + * through DSP command format (0xfc), addr (0xc4), data (0xc5) and cmd (0xc6)
- + * register. It has to wait until the DSP is ready.
- + *
- + * Returns 0 for success or negative error code.
- + */
- +static int rt5640_dsp_write(struct snd_soc_codec *codec,
- + struct rt5640_dsp_param *param)
- +{
- + unsigned int dsp_val = snd_soc_read(codec, RT5640_DSP_CTRL3);
- + int ret;
- +
- + ret = rt5640_dsp_done(codec);
- + if (ret < 0) {
- + dev_err(codec->dev, "DSP is busy: %d\n", ret);
- + goto err;
- + }
- + ret = snd_soc_write(codec, RT5640_DUMMY3, param->cmd_fmt);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to write cmd format: %d\n", ret);
- + goto err;
- + }
- + ret = snd_soc_write(codec, RT5640_DSP_CTRL1, param->addr);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to write DSP addr reg: %d\n", ret);
- + goto err;
- + }
- + ret = snd_soc_write(codec, RT5640_DSP_CTRL2, param->data);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to write DSP data reg: %d\n", ret);
- + goto err;
- + }
- + dsp_val &= ~(RT5640_DSP_R_EN | RT5640_DSP_CMD_MASK);
- + dsp_val |= RT5640_DSP_W_EN | param->cmd;
- + ret = snd_soc_write(codec, RT5640_DSP_CTRL3, dsp_val);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to write DSP cmd reg: %d\n", ret);
- + goto err;
- + }
- + mdelay(10);
- + return 0;
- +
- +err:
- + return ret;
- +}
- +
- +/**
- + * rt5640_dsp_read - Read DSP register.
- + * @codec: SoC audio codec device.
- + * @reg: DSP register index.
- + *
- + * Read DSP setting value from voice DSP. The DSP can be controlled
- + * through DSP addr (0xc4), data (0xc5) and cmd (0xc6) register. Each
- + * command has to wait until the DSP is ready.
- + *
- + * Returns DSP register value or negative error code.
- + */
- +static unsigned int rt5640_dsp_read(
- + struct snd_soc_codec *codec, unsigned int reg)
- +{
- + unsigned int val_h, val_l, value;
- + unsigned int dsp_val = snd_soc_read(codec, RT5640_DSP_CTRL3);
- + int ret = 0;
- +
- + ret = rt5640_dsp_done(codec);
- + if (ret < 0) {
- + dev_err(codec->dev, "DSP is busy: %d\n", ret);
- + goto err;
- + }
- + ret = snd_soc_write(codec, RT5640_DUMMY3, 0);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to write fc = 0: %d\n", ret);
- + goto err;
- + }
- + ret = snd_soc_write(codec, RT5640_DSP_CTRL1, reg);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to write DSP addr reg: %d\n", ret);
- + goto err;
- + }
- + dsp_val &= ~(RT5640_DSP_W_EN | RT5640_DSP_CMD_MASK);
- + dsp_val |= RT5640_DSP_R_EN | RT5640_DSP_CMD_MR;
- + ret = snd_soc_write(codec, RT5640_DSP_CTRL3, dsp_val);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to write DSP cmd reg: %d\n", ret);
- + goto err;
- + }
- +
- + /* Read DSP high byte data */
- + ret = rt5640_dsp_done(codec);
- + if (ret < 0) {
- + dev_err(codec->dev, "DSP is busy: %d\n", ret);
- + goto err;
- + }
- + ret = snd_soc_write(codec, RT5640_DSP_CTRL1, RT5640_DSP_REG_DATHI);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to write DSP addr reg: %d\n", ret);
- + goto err;
- + }
- + dsp_val &= ~(RT5640_DSP_W_EN | RT5640_DSP_CMD_MASK);
- + dsp_val |= RT5640_DSP_R_EN | RT5640_DSP_CMD_RR;
- + ret = snd_soc_write(codec, RT5640_DSP_CTRL3, dsp_val);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to write DSP cmd reg: %d\n", ret);
- + goto err;
- + }
- + ret = rt5640_dsp_done(codec);
- + if (ret < 0) {
- + dev_err(codec->dev, "DSP is busy: %d\n", ret);
- + goto err;
- + }
- + ret = snd_soc_read(codec, RT5640_DSP_CTRL2);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to read DSP data reg: %d\n", ret);
- + goto err;
- + }
- + val_h = ret;
- +
- + /* Read DSP low byte data */
- + ret = snd_soc_write(codec, RT5640_DSP_CTRL1, RT5640_DSP_REG_DATLO);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to write DSP addr reg: %d\n", ret);
- + goto err;
- + }
- + ret = snd_soc_write(codec, RT5640_DSP_CTRL3, dsp_val);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to write DSP cmd reg: %d\n", ret);
- + goto err;
- + }
- + ret = rt5640_dsp_done(codec);
- + if (ret < 0) {
- + dev_err(codec->dev, "DSP is busy: %d\n", ret);
- + goto err;
- + }
- + ret = snd_soc_read(codec, RT5640_DSP_CTRL2);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to read DSP data reg: %d\n", ret);
- + goto err;
- + }
- + val_l = ret;
- +
- + value = ((val_h & 0xff) << 8) |(val_l & 0xff);
- + return value;
- +
- +err:
- + return ret;
- +}
- +
- +static int rt5640_dsp_get(struct snd_kcontrol *kcontrol,
- + struct snd_ctl_elem_value *ucontrol)
- +{
- + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
- +
- + ucontrol->value.integer.value[0] = rt5640->dsp_sw;
- +
- + return 0;
- +}
- +
- +static int rt5640_dsp_put(struct snd_kcontrol *kcontrol,
- + struct snd_ctl_elem_value *ucontrol)
- +{
- + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
- +
- + if (rt5640->dsp_sw != ucontrol->value.integer.value[0])
- + rt5640->dsp_sw = ucontrol->value.integer.value[0];
- +
- + return 0;
- + }
- +
- +static int rt5640_dsp_play_bp_get(struct snd_kcontrol *kcontrol,
- + struct snd_ctl_elem_value *ucontrol)
- +{
- + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
- +
- + ucontrol->value.integer.value[0] = rt5640->dsp_play_pass;
- +
- + return 0;
- +}
- +
- +static int rt5640_dsp_play_bp_put(struct snd_kcontrol *kcontrol,
- + struct snd_ctl_elem_value *ucontrol)
- +{
- + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
- +
- + if (rt5640->dsp_play_pass == ucontrol->value.integer.value[0])
- + return 0;
- + rt5640->dsp_play_pass = ucontrol->value.integer.value[0];
- +
- + rt5640_conn_mux_path(codec, "DAC L2 Mux",
- + rt5640->dsp_play_pass ? "IF2" : "TxDC");
- + rt5640_conn_mux_path(codec, "DAC R2 Mux",
- + rt5640->dsp_play_pass ? "IF2" : "TxDC");
- + rt5640_conn_mixer_path(codec, "Stereo DAC MIXL",
- + "DAC L1 Switch", rt5640->dsp_play_pass);
- + rt5640_conn_mixer_path(codec, "Stereo DAC MIXL",
- + "DAC L2 Switch", !rt5640->dsp_play_pass);
- + rt5640_conn_mixer_path(codec, "Stereo DAC MIXR",
- + "DAC R1 Switch", rt5640->dsp_play_pass);
- + rt5640_conn_mixer_path(codec, "Stereo DAC MIXR",
- + "DAC R2 Switch", !rt5640->dsp_play_pass);
- +
- + return 0;
- +}
- +
- +static int rt5640_dsp_rec_bp_get(struct snd_kcontrol *kcontrol,
- + struct snd_ctl_elem_value *ucontrol)
- +{
- + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
- +
- + ucontrol->value.integer.value[0] = rt5640->dsp_rec_pass;
- +
- + return 0;
- +}
- +
- +static int rt5640_dsp_rec_bp_put(struct snd_kcontrol *kcontrol,
- + struct snd_ctl_elem_value *ucontrol)
- +{
- + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
- +
- + if (rt5640->dsp_rec_pass == ucontrol->value.integer.value[0])
- + return 0;
- + rt5640->dsp_rec_pass = ucontrol->value.integer.value[0];
- +
- + rt5640_conn_mux_path(codec, "IF2 ADC L Mux",
- + rt5640->dsp_rec_pass ? "Mono ADC MIXL" : "TxDP");
- + rt5640_conn_mux_path(codec, "IF2 ADC R Mux",
- + rt5640->dsp_rec_pass ? "Mono ADC MIXR" : "TxDP");
- + rt5640_conn_mixer_path(codec, "Stereo ADC MIXL",
- + "ADC1 Switch", rt5640->dsp_rec_pass);
- + rt5640_conn_mixer_path(codec, "Stereo ADC MIXR",
- + "ADC1 Switch", rt5640->dsp_rec_pass);
- + rt5640_conn_mixer_path(codec, "Mono ADC MIXL",
- + "ADC1 Switch", !rt5640->dsp_rec_pass);
- + rt5640_conn_mixer_path(codec, "Mono ADC MIXR",
- + "ADC1 Switch", !rt5640->dsp_rec_pass);
- +
- + return 0;
- +}
- +
- +static int rt5640_dac_active_get(struct snd_kcontrol *kcontrol,
- + struct snd_ctl_elem_value *ucontrol)
- +{
- + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- + struct snd_soc_dapm_context *dapm = &codec->dapm;
- + struct snd_soc_dapm_widget *w;
- +
- + list_for_each_entry(w, &dapm->card->widgets, list)
- + {
- + if (!w->sname || w->dapm != dapm)
- + continue;
- + if (strstr(w->sname, "Playback")) {
- + pr_info("widget %s %s\n", w->name, w->sname);
- + ucontrol->value.integer.value[0] = w->active;
- + break;
- + }
- + }
- + return 0;
- +}
- +
- +static int rt5640_dac_active_put(struct snd_kcontrol *kcontrol,
- + struct snd_ctl_elem_value *ucontrol)
- +{
- + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- + struct snd_soc_dapm_context *dapm = &codec->dapm;
- + struct snd_soc_dapm_widget *w;
- +
- + list_for_each_entry(w, &dapm->card->widgets, list)
- + {
- + if (!w->sname || w->dapm != dapm)
- + continue;
- + if (strstr(w->sname, "Playback")) {
- + pr_info("widget %s %s\n", w->name, w->sname);
- + w->active = 1;
- + }
- + }
- + return 0;
- +}
- +
- +static int rt5640_adc_active_get(struct snd_kcontrol *kcontrol,
- + struct snd_ctl_elem_value *ucontrol)
- +{
- + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- + struct snd_soc_dapm_context *dapm = &codec->dapm;
- + struct snd_soc_dapm_widget *w;
- +
- + list_for_each_entry(w, &dapm->card->widgets, list)
- + {
- + if (!w->sname || w->dapm != dapm)
- + continue;
- + if (strstr(w->sname, "Capture")) {
- + pr_info("widget %s %s\n", w->name, w->sname);
- + ucontrol->value.integer.value[0] = w->active;
- + break;
- + }
- + }
- + return 0;
- +}
- +
- +static int rt5640_adc_active_put(struct snd_kcontrol *kcontrol,
- + struct snd_ctl_elem_value *ucontrol)
- +{
- + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- + struct snd_soc_dapm_context *dapm = &codec->dapm;
- + struct snd_soc_dapm_widget *w;
- +
- + list_for_each_entry(w, &dapm->card->widgets, list)
- + {
- + if (!w->sname || w->dapm != dapm)
- + continue;
- + if (strstr(w->sname, "Capture")) {
- + pr_info("widget %s %s\n", w->name, w->sname);
- + w->active = 1;
- + }
- + }
- + return 0;
- +}
- +
- +/* DSP Path Control 1 */
- +static const char *rt5640_src_rxdp_mode[] = {
- + "Normal", "Divided by 3"};
- +
- +static const SOC_ENUM_SINGLE_DECL(
- + rt5640_src_rxdp_enum, RT5640_DSP_PATH1,
- + RT5640_RXDP_SRC_SFT, rt5640_src_rxdp_mode);
- +
- +static const char *rt5640_src_txdp_mode[] = {
- + "Normal", "Multiplied by 3"};
- +
- +static const SOC_ENUM_SINGLE_DECL(
- + rt5640_src_txdp_enum, RT5640_DSP_PATH1,
- + RT5640_TXDP_SRC_SFT, rt5640_src_txdp_mode);
- +
- +/* DSP data select */
- +static const char *rt5640_dsp_data_select[] = {
- + "Normal", "left copy to right", "right copy to left", "Swap"};
- +
- +static const SOC_ENUM_SINGLE_DECL(rt5640_rxdc_data_enum, RT5640_DSP_PATH2,
- + RT5640_RXDC_SEL_SFT, rt5640_dsp_data_select);
- +
- +static const SOC_ENUM_SINGLE_DECL(rt5640_rxdp_data_enum, RT5640_DSP_PATH2,
- + RT5640_RXDP_SEL_SFT, rt5640_dsp_data_select);
- +
- +static const SOC_ENUM_SINGLE_DECL(rt5640_txdc_data_enum, RT5640_DSP_PATH2,
- + RT5640_TXDC_SEL_SFT, rt5640_dsp_data_select);
- +
- +static const SOC_ENUM_SINGLE_DECL(rt5640_txdp_data_enum, RT5640_DSP_PATH2,
- + RT5640_TXDP_SEL_SFT, rt5640_dsp_data_select);
- +
- +/* Sound Effect */
- +static const char *rt5640_dsp_mode[] = {
- + "Disable", "AEC+NS+FENS", "HFBF", "Far Field Pick-up"};
- +
- +static const SOC_ENUM_SINGLE_DECL(rt5640_dsp_enum, 0, 0, rt5640_dsp_mode);
- +
- +static const struct snd_kcontrol_new rt5640_dsp_snd_controls[] = {
- + SOC_ENUM("RxDC input data", rt5640_rxdc_data_enum),
- + SOC_ENUM("RxDP input data", rt5640_rxdp_data_enum),
- + SOC_ENUM("TxDC input data", rt5640_txdc_data_enum),
- + SOC_ENUM("TxDP input data", rt5640_txdp_data_enum),
- + SOC_ENUM("SRC for RxDP", rt5640_src_rxdp_enum),
- + SOC_ENUM("SRC for TxDP", rt5640_src_txdp_enum),
- + /* AEC */
- + SOC_ENUM_EXT("DSP Function Switch", rt5640_dsp_enum,
- + rt5640_dsp_get, rt5640_dsp_put),
- + SOC_SINGLE_EXT("DSP Playback Bypass", 0, 0, 1, 0,
- + rt5640_dsp_play_bp_get, rt5640_dsp_play_bp_put),
- + SOC_SINGLE_EXT("DSP Record Bypass", 0, 0, 1, 0,
- + rt5640_dsp_rec_bp_get, rt5640_dsp_rec_bp_put),
- + SOC_SINGLE_EXT("DAC Switch", 0, 0, 1, 0,
- + rt5640_dac_active_get, rt5640_dac_active_put),
- + SOC_SINGLE_EXT("ADC Switch", 0, 0, 1, 0,
- + rt5640_adc_active_get, rt5640_adc_active_put),
- +};
- +
- +static int rt5640_dsp_patch_3(struct snd_soc_codec *codec)
- +{
- + struct rt5640_dsp_param param;
- + int ret, i;
- +
- + param.cmd_fmt = 0x0090;
- + param.addr = 0x0064;
- + param.data = 0x0004;
- + param.cmd = RT5640_DSP_CMD_RW;
- + ret = rt5640_dsp_write(codec, ¶m);
- + if (ret < 0) {
- + dev_err(codec->dev,
- + "Fail to set DSP 3 bytes patch entrance: %d\n", ret);
- + goto patch_err;
- + }
- +
- + param.cmd = RT5640_DSP_CMD_PE;
- + for(i = 0; i < RT5640_DSP_PATCH3_NUM; i++) {
- + param.cmd_fmt = rt5640_dsp_p3_tab[i][0];
- + param.addr = rt5640_dsp_p3_tab[i][1];
- + param.data = rt5640_dsp_p3_tab[i][2];
- + ret = rt5640_dsp_write(codec, ¶m);
- + if (ret < 0) {
- + dev_err(codec->dev, "Fail to patch Dsp: %d\n", ret);
- + goto patch_err;
- + }
- + }
- +
- + return 0;
- +
- +patch_err:
- +
- + return ret;
- +}
- +
- +static int rt5640_dsp_patch_2(struct snd_soc_codec *codec)
- +{
- + struct rt5640_dsp_param param;
- + int ret, i;
- +
- + param.cmd_fmt = 0x0090;
- + param.addr = 0x0064;
- + param.data = 0x0000;
- + param.cmd = RT5640_DSP_CMD_RW;
- + ret = rt5640_dsp_write(codec, ¶m);
- + if (ret < 0) {
- + dev_err(codec->dev,
- + "Fail to set DSP 2 bytes patch entrance: %d\n", ret);
- + goto patch_err;
- + }
- +
- + param.cmd_fmt = 0x00e0;
- + param.cmd = RT5640_DSP_CMD_MW;
- + for(i = 0; i < RT5640_DSP_PATCH2_NUM; i++) {
- + param.addr = rt5640_dsp_p2_tab[i][0];
- + param.data = rt5640_dsp_p2_tab[i][1];
- + ret = rt5640_dsp_write(codec, ¶m);
- + if (ret < 0) {
- + dev_err(codec->dev, "Fail to patch Dsp: %d\n", ret);
- + goto patch_err;
- + }
- + }
- +
- + return 0;
- +
- +patch_err:
- +
- + return ret;
- +}
- +
- +/**
- + * rt5640_dsp_patch - Write DSP patch code.
- + *
- + * @codec: SoC audio codec device.
- + *
- + * Write patch codes to DSP including 3 and 2 bytes data.
- + *
- + * Returns 0 for success or negative error code.
- + */
- +static int rt5640_dsp_patch(struct snd_soc_codec *codec)
- +{
- + int ret;
- +
- + dev_dbg(codec->dev, "\n DSP Patch Start ......\n");
- +
- + ret = snd_soc_update_bits(codec, RT5640_MICBIAS,
- + RT5640_PWR_CLK25M_MASK, RT5640_PWR_CLK25M_PU);
- + if (ret < 0)
- + goto patch_err;
- +
- + ret = snd_soc_update_bits(codec, RT5640_GLB_CLK,
- + RT5640_SCLK_SRC_MASK, RT5640_SCLK_SRC_RCCLK);
- + if (ret < 0)
- + goto patch_err;
- +
- + ret = snd_soc_update_bits(codec, RT5640_PWR_DIG2,
- + RT5640_PWR_I2S_DSP, RT5640_PWR_I2S_DSP);
- + if (ret < 0)
- + goto patch_err;
- +
- + ret = snd_soc_update_bits(codec, RT5640_DSP_CTRL3,
- + RT5640_DSP_PD_PIN_MASK, RT5640_DSP_PD_PIN_HI);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to power up DSP: %d\n", ret);
- + goto patch_err;
- + }
- +
- + ret = snd_soc_update_bits(codec, RT5640_DSP_CTRL3,
- + RT5640_DSP_RST_PIN_MASK, RT5640_DSP_RST_PIN_LO);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to reset DSP: %d\n", ret);
- + goto patch_err;
- + }
- +
- + mdelay(10);
- +
- + ret = snd_soc_update_bits(codec, RT5640_DSP_CTRL3,
- + RT5640_DSP_RST_PIN_MASK, RT5640_DSP_RST_PIN_HI);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to recover DSP: %d\n", ret);
- + goto patch_err;
- + }
- +
- + ret = rt5640_dsp_patch_3(codec);
- + if (ret < 0)
- + goto patch_err;
- +
- + ret = rt5640_dsp_patch_2(codec);
- + if (ret < 0)
- + goto patch_err;
- +
- + return 0;
- +
- +patch_err:
- +
- + return ret;
- +}
- +
- +static void rt5640_do_dsp_patch(struct work_struct *work)
- +{
- + struct rt5640_priv *rt5640 =
- + container_of(work, struct rt5640_priv, patch_work.work);
- + struct snd_soc_codec *codec = rt5640->codec;
- +
- + if (rt5640_dsp_patch(codec) < 0)
- + dev_err(codec->dev, "Patch DSP rom code Fail !!!\n");
- +}
- +
- +
- +/**
- + * rt5640_dsp_conf - Set DSP basic setting.
- + *
- + * @codec: SoC audio codec device.
- + *
- + * Set parameters of basic setting to DSP.
- + *
- + * Returns 0 for success or negative error code.
- + */
- +static int rt5640_dsp_conf(struct snd_soc_codec *codec)
- +{
- + struct rt5640_dsp_param param;
- + int ret, i;
- +
- + ret = snd_soc_update_bits(codec, RT5640_DSP_CTRL3,
- + RT5640_DSP_PD_PIN_MASK, RT5640_DSP_PD_PIN_HI);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to power up DSP: %d\n", ret);
- + goto conf_err;
- + }
- +
- + ret = snd_soc_update_bits(codec, RT5640_DSP_CTRL3,
- + RT5640_DSP_RST_PIN_MASK, RT5640_DSP_RST_PIN_LO);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to reset DSP: %d\n", ret);
- + goto conf_err;
- + }
- +
- + mdelay(10);
- +
- + ret = snd_soc_update_bits(codec, RT5640_DSP_CTRL3,
- + RT5640_DSP_RST_PIN_MASK | RT5640_DSP_CLK_MASK,
- + RT5640_DSP_RST_PIN_HI | RT5640_DSP_CLK_384K);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to recover DSP: %d\n", ret);
- + goto conf_err;
- + }
- +
- + param.cmd_fmt = 0x00e0;
- + param.cmd = RT5640_DSP_CMD_MW;
- + for(i = 0; i < RT5640_DSP_INIT_NUM; i++) {
- + param.addr = rt5640_dsp_init[i][0];
- + param.data = rt5640_dsp_init[i][1];
- + ret = rt5640_dsp_write(codec, ¶m);
- + if (ret < 0) {
- + dev_err(codec->dev, "Fail to config Dsp: %d\n", ret);
- + goto conf_err;
- + }
- + }
- +
- + return 0;
- +
- +conf_err:
- +
- + return ret;
- +}
- +
- +/**
- + * rt5640_dsp_rate - Set DSP rate setting.
- + *
- + * @codec: SoC audio codec device.
- + * @rate: Sampling rate.
- + *
- + * Set parameters of sampling rate to DSP.
- + *
- + * Returns 0 for success or negative error code.
- + */
- +static int rt5640_dsp_rate(struct snd_soc_codec *codec, int rate)
- +{
- + struct rt5640_dsp_param param;
- + int ret, i, tab_num;
- + unsigned short (*rate_tab)[2];
- +
- + if (rate != 48000 && rate != 44100 && rate != 16000)
- + return -EINVAL;
- +
- + if (rate > 44100) {
- + rate_tab = rt5640_dsp_48;
- + tab_num = RT5640_DSP_48_NUM;
- + } else {
- + if (rate > 16000) {
- + rate_tab = rt5640_dsp_441;
- + tab_num = RT5640_DSP_441_NUM;
- + } else {
- + rate_tab = rt5640_dsp_16;
- + tab_num = RT5640_DSP_16_NUM;
- + }
- + }
- +
- + param.cmd_fmt = 0x00e0;
- + param.cmd = RT5640_DSP_CMD_MW;
- + for (i = 0; i < tab_num; i++) {
- + param.addr = rate_tab[i][0];
- + param.data = rate_tab[i][1];
- + ret = rt5640_dsp_write(codec, ¶m);
- + if (ret < 0)
- + goto rate_err;
- + }
- +
- + return 0;
- +
- +rate_err:
- +
- + dev_err(codec->dev, "Fail to set rate %d parameters: %d\n", rate, ret);
- + return ret;
- +}
- +
- +/**
- + * rt5640_dsp_set_mode - Set DSP mode parameters.
- + *
- + * @codec: SoC audio codec device.
- + * @mode: DSP mode.
- + *
- + * Set parameters of mode to DSP.
- + * There are three modes which includes " mic AEC + NS + FENS",
- + * "HFBF" and "Far-field pickup".
- + *
- + * Returns 0 for success or negative error code.
- + */
- +static int rt5640_dsp_set_mode(struct snd_soc_codec *codec, int mode)
- +{
- + struct rt5640_dsp_param param;
- + int ret, i, tab_num;
- + unsigned short (*mode_tab)[2];
- +
- + switch (mode) {
- + case RT5640_DSP_AEC_NS_FENS:
- + dev_info(codec->dev, "AEC\n");
- + mode_tab = rt5640_dsp_aec_ns_fens;
- + tab_num = RT5640_DSP_AEC_NUM;
- + break;
- +
- + case RT5640_DSP_HFBF:
- + dev_info(codec->dev, "Beamforming\n");
- + mode_tab = rt5640_dsp_hfbf;
- + tab_num = RT5640_DSP_HFBF_NUM;
- + break;
- +
- + case RT5640_DSP_FFP:
- + dev_info(codec->dev, "Far Field Pick-up\n");
- + mode_tab = rt5640_dsp_ffp;
- + tab_num = RT5640_DSP_FFP_NUM;
- + break;
- +
- + case RT5640_DSP_DIS:
- + default:
- + dev_info(codec->dev, "Disable\n");
- + return 0;
- + }
- +
- + param.cmd_fmt = 0x00e0;
- + param.cmd = RT5640_DSP_CMD_MW;
- + for (i = 0; i < tab_num; i++) {
- + param.addr = mode_tab[i][0];
- + param.data = mode_tab[i][1];
- + ret = rt5640_dsp_write(codec, ¶m);
- + if (ret < 0)
- + goto mode_err;
- + }
- +
- + return 0;
- +
- +mode_err:
- +
- + dev_err(codec->dev, "Fail to set mode %d parameters: %d\n", mode, ret);
- + return ret;
- +}
- +
- +/**
- + * rt5640_dsp_snd_effect - Set DSP sound effect.
- + *
- + * Set parameters of sound effect to DSP.
- + *
- + * Returns 0 for success or negative error code.
- + */
- +static int rt5640_dsp_snd_effect(struct snd_soc_codec *codec)
- +{
- + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
- + int ret;
- +
- +
- +
- + ret = rt5640_dsp_conf(codec);
- + if (ret < 0)
- + goto effect_err;
- +
- + ret = rt5640_dsp_rate(codec, rt5640->lrck[rt5640->aif_pu] ?
- + rt5640->lrck[rt5640->aif_pu] : 44100);
- + if (ret < 0)
- + goto effect_err;
- +
- + ret = rt5640_dsp_set_mode(codec, rt5640->dsp_sw);
- + if (ret < 0)
- + goto effect_err;
- +
- + mdelay(20);
- +
- + return 0;
- +
- +effect_err:
- +
- + return ret;
- +}
- +
- +static int rt5640_dsp_event(struct snd_soc_dapm_widget *w,
- + struct snd_kcontrol *k, int event)
- +{
- + struct snd_soc_codec *codec = w->codec;
- + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
- + static unsigned int power_on;
- +
- + switch (event) {
- + case SND_SOC_DAPM_POST_PMD:
- + pr_info("%s(): PMD\n", __func__);
- + if (!power_on)
- + return 0;
- + power_on--;
- + if (!power_on) {
- + snd_soc_update_bits(codec, RT5640_PWR_DIG2,
- + RT5640_PWR_I2S_DSP, 0);
- + snd_soc_update_bits(codec, RT5640_DSP_CTRL3,
- + RT5640_DSP_PD_PIN_MASK, RT5640_DSP_PD_PIN_LO);
- + }
- + break;
- +
- + case SND_SOC_DAPM_PRE_PMU:
- + pr_info("%s(): PMU\n", __func__);
- + if (rt5640->dsp_sw == RT5640_DSP_DIS || 2 <= power_on)
- + return 0;
- + if (!power_on) {
- + snd_soc_update_bits(codec, RT5640_PWR_DIG2,
- + RT5640_PWR_I2S_DSP, RT5640_PWR_I2S_DSP);
- + rt5640_dsp_snd_effect(codec);
- + }
- + power_on++;
- + break;
- +
- + default:
- + return 0;
- + }
- +
- + return 0;
- +}
- +
- +static const struct snd_soc_dapm_widget rt5640_dsp_dapm_widgets[] = {
- + SND_SOC_DAPM_PGA_E("DSP Downstream", SND_SOC_NOPM,
- + 0, 0, NULL, 0, rt5640_dsp_event,
- + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
- + SND_SOC_DAPM_PGA_E("DSP Upstream", SND_SOC_NOPM,
- + 0, 0, NULL, 0, rt5640_dsp_event,
- + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
- + SND_SOC_DAPM_PGA("RxDP", SND_SOC_NOPM, 0, 0, NULL, 0),
- + SND_SOC_DAPM_PGA("RxDC", SND_SOC_NOPM, 0, 0, NULL, 0),
- + SND_SOC_DAPM_PGA("TxDC", SND_SOC_NOPM, 0, 0, NULL, 0),
- + SND_SOC_DAPM_PGA("TxDP", SND_SOC_NOPM, 0, 0, NULL, 0),
- +};
- +
- +static const struct snd_soc_dapm_route rt5640_dsp_dapm_routes[] = {
- + {"RxDC", NULL, "Mono ADC MIXL"},
- + {"RxDC", NULL, "Mono ADC MIXR"},
- + {"RxDP", NULL, "IF2 DAC L"},
- + {"RxDP", NULL, "IF2 DAC R"},
- +
- + {"DSP Downstream", NULL, "RxDP"},
- + {"TxDC", NULL, "DSP Downstream"},
- + {"DSP Upstream", NULL, "RxDC"},
- + {"TxDP", NULL, "DSP Upstream"},
- +
- + {"IF2 ADC L Mux", "TxDP", "TxDP"},
- + {"IF2 ADC R Mux", "TxDP", "TxDP"},
- + {"DAC L2 Mux", "TxDC", "TxDC"},
- + {"DAC R2 Mux", "TxDC", "TxDC"},
- +};
- +
- +/**
- + * rt5640_dsp_show - Dump DSP registers.
- + * @dev: codec device.
- + * @attr: device attribute.
- + * @buf: buffer for display.
- + *
- + * To show non-zero values of all DSP registers.
- + *
- + * Returns buffer length.
- + */
- +static ssize_t rt5640_dsp_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct i2c_client *client = to_i2c_client(dev);
- + struct rt5640_priv *rt5640 = i2c_get_clientdata(client);
- + struct snd_soc_codec *codec = rt5640->codec;
- + unsigned short (*rt5640_dsp_tab)[2];
- + unsigned int val;
- + int cnt = 0, i, tab_num;
- +
- + switch (rt5640->dsp_sw) {
- + case RT5640_DSP_AEC_NS_FENS:
- + cnt += sprintf(buf, "[ RT5642 DSP 'AEC' ]\n");
- + rt5640_dsp_tab = rt5640_dsp_aec_ns_fens;
- + tab_num = RT5640_DSP_AEC_NUM;
- + break;
- +
- + case RT5640_DSP_HFBF:
- + cnt += sprintf(buf, "[ RT5642 DSP 'Beamforming' ]\n");
- + rt5640_dsp_tab = rt5640_dsp_hfbf;
- + tab_num = RT5640_DSP_HFBF_NUM;
- + break;
- +
- + case RT5640_DSP_FFP:
- + cnt += sprintf(buf, "[ RT5642 DSP 'Far Field Pick-up' ]\n");
- + rt5640_dsp_tab = rt5640_dsp_ffp;
- + tab_num = RT5640_DSP_FFP_NUM;
- + break;
- +
- + case RT5640_DSP_DIS:
- + default:
- + cnt += sprintf(buf, "RT5642 DSP Disabled\n");
- + goto dsp_done;
- + }
- +
- + for (i = 0; i < tab_num; i++) {
- + if (cnt + RT5640_DSP_REG_DISP_LEN >= PAGE_SIZE)
- + break;
- + val = rt5640_dsp_read(codec, rt5640_dsp_tab[i][0]);
- + if (!val)
- + continue;
- + cnt += snprintf(buf + cnt, RT5640_DSP_REG_DISP_LEN,
- + "%04x: %04x\n", rt5640_dsp_tab[i][0], val);
- + }
- +
- +dsp_done:
- +
- + if (cnt >= PAGE_SIZE)
- + cnt = PAGE_SIZE - 1;
- +
- + return cnt;
- +}
- +static DEVICE_ATTR(dsp_reg, 0444, rt5640_dsp_show, NULL);
- +
- +/**
- + * rt5640_dsp_probe - register DSP for rt5640
- + * @codec: audio codec
- + *
- + * To register DSP function for rt5640.
- + *
- + * Returns 0 for success or negative error code.
- + */
- +int rt5640_dsp_probe(struct snd_soc_codec *codec)
- +{
- + struct rt5640_priv *rt5640;
- + int ret;
- +
- + if (codec == NULL)
- + return -EINVAL;
- +
- + snd_soc_add_controls(codec, rt5640_dsp_snd_controls,
- + ARRAY_SIZE(rt5640_dsp_snd_controls));
- + snd_soc_dapm_new_controls(&codec->dapm, rt5640_dsp_dapm_widgets,
- + ARRAY_SIZE(rt5640_dsp_dapm_widgets));
- + snd_soc_dapm_add_routes(&codec->dapm, rt5640_dsp_dapm_routes,
- + ARRAY_SIZE(rt5640_dsp_dapm_routes));
- +
- + /* Patch DSP rom code if IC version is larger than C version */
- + //if (RT5640_VER_C != snd_soc_read(codec, RT5640_VENDOR_ID)) {
- + ret = snd_soc_update_bits(codec, RT5640_PWR_DIG2,
- + RT5640_PWR_I2S_DSP, RT5640_PWR_I2S_DSP);
- + if (ret < 0) {
- + dev_err(codec->dev,
- + "Failed to power up DSP IIS interface: %d\n", ret);
- + }
- + rt5640_dsp_conf(codec);
- + ret = rt5640_dsp_read(codec, 0x3800);
- + pr_info("DSP version code = 0x%04x\n",ret);
- + if(ret != 0x501a) {
- + rt5640 = snd_soc_codec_get_drvdata(codec);
- + INIT_DELAYED_WORK(&rt5640->patch_work, rt5640_do_dsp_patch);
- + schedule_delayed_work(&rt5640->patch_work,
- + msecs_to_jiffies(100));
- + }
- + snd_soc_update_bits(codec, RT5640_PWR_DIG2,
- + RT5640_PWR_I2S_DSP, 0);
- +
- + ret = device_create_file(codec->dev, &dev_attr_dsp_reg);
- + if (ret != 0) {
- + dev_err(codec->dev,
- + "Failed to create index_reg sysfs files: %d\n", ret);
- + return ret;
- + }
- +
- + return 0;
- +}
- +EXPORT_SYMBOL_GPL(rt5640_dsp_probe);
- +
- +int do_rt5640_dsp_set_mode(struct snd_soc_codec *codec, int mode) {
- + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
- +
- + if(DBG) printk("%s mode=%d\n",__func__,mode);
- +
- + if(rt5640->dsp_sw == mode)
- + return 0;
- + rt5640->dsp_sw = mode;
- +
- + if(rt5640->dsp_sw == RT5640_DSP_DIS) {
- + rt5640->dsp_play_pass = rt5640->dsp_rec_pass = 1;
- + snd_soc_update_bits(codec, RT5640_DSP_PATH1,
- + RT5640_RXDP_SRC_MASK | RT5640_TXDP_SRC_MASK, 0);
- + snd_soc_update_bits(codec, RT5640_ASRC_1,
- + RT5640_M1_T_MASK, RT5640_M1_T_I2S2);
- + } else {
- + rt5640->dsp_play_pass = rt5640->dsp_rec_pass = 0;
- + }
- + rt5640_conn_mux_path(codec, "SDI1 TX Mux",
- + rt5640->dsp_play_pass ? "IF1" : "IF2");
- + //Stereo DAC MIXL
- + rt5640_conn_mixer_path(codec, "Stereo DAC MIXL",
- + "DAC L1 Switch", rt5640->dsp_play_pass);
- + rt5640_conn_mixer_path(codec, "Stereo DAC MIXL",
- + "DAC L2 Switch", !rt5640->dsp_play_pass);
- + rt5640_conn_mixer_path(codec, "Stereo DAC MIXR",
- + "DAC R1 Switch", rt5640->dsp_play_pass);
- + rt5640_conn_mixer_path(codec, "Stereo DAC MIXR",
- + "DAC R2 Switch", !rt5640->dsp_play_pass);
- + //Stereo ADC MIXL
- + rt5640_conn_mixer_path(codec, "Stereo ADC MIXL", "ADC1 Switch", true);
- + rt5640_conn_mixer_path(codec, "Stereo ADC MIXR", "ADC1 Switch", true);
- + rt5640_conn_mixer_path(codec, "Stereo ADC MIXL",
- + "ADC2 Switch", rt5640->dsp_rec_pass);
- + rt5640_conn_mixer_path(codec, "Stereo ADC MIXR",
- + "ADC2 Switch", rt5640->dsp_rec_pass);
- + //Mono ADC MIXL
- + rt5640_conn_mixer_path(codec, "Mono ADC MIXL",
- + "ADC2 Switch", !rt5640->dsp_rec_pass);
- + rt5640_conn_mixer_path(codec, "Mono ADC MIXR",
- + "ADC2 Switch", !rt5640->dsp_rec_pass);
- + return 0;
- +}
- +
- +EXPORT_SYMBOL_GPL(do_rt5640_dsp_set_mode);
- +
- +#ifdef RTK_IOCTL
- +int rt56xx_dsp_ioctl_common(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
- +{
- + struct rt56xx_cmd rt56xx;
- + int *buf;
- + int *p;
- + int ret;
- + struct rt5640_dsp_param param;
- +
- + //int mask1 = 0, mask2 = 0;
- +
- + struct rt56xx_cmd __user *_rt56xx =(struct rt56xx_cmd *)arg;
- + struct snd_soc_codec *codec = hw->private_data;
- + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
- +
- + if (copy_from_user(&rt56xx, _rt56xx, sizeof(rt56xx))) {
- + printk("copy_from_user faild\n");
- + return -EFAULT;
- + }
- + if(DBG) printk("rt56xx.number=%d\n",rt56xx.number);
- + buf = kmalloc(sizeof(*buf) * rt56xx.number, GFP_KERNEL);
- + if (buf == NULL)
- + return -ENOMEM;
- + if (copy_from_user(buf, rt56xx.buf, sizeof(*buf) * rt56xx.number)) {
- + goto err;
- + }
- +
- + ret = snd_soc_update_bits(codec, RT5640_PWR_DIG2,
- + RT5640_PWR_I2S_DSP, RT5640_PWR_I2S_DSP);
- + if (ret < 0) {
- + dev_err(codec->dev,
- + "Failed to power up DSP IIS interface: %d\n", ret);
- + goto err;
- + }
- + /*
- + ret = rt5640_dsp_conf(codec);
- + if (ret < 0)
- + goto err;
- + */
- +
- + switch (cmd) {
- + case RT_READ_CODEC_DSP_IOCTL:
- + if(DBG) printk(" case RT_READ_CODEC_DSP_IOCTL\n");
- +
- + for (p = buf; p < buf + rt56xx.number/2; p++)
- + {
- + *(p+rt56xx.number/2) = rt5640_dsp_read(codec, *p);
- + }
- + if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * rt56xx.number))
- + goto err;
- +
- + break;
- + case RT_WRITE_CODEC_DSP_IOCTL:
- + if(DBG) printk(" case RT_WRITE_CODEC_DSP_IOCTL\n");
- +
- + param.cmd_fmt = 0x00e0;
- + param.cmd = RT5640_DSP_CMD_MW;
- + p = buf;
- + param.addr = *p;
- + param.data = *(p+rt56xx.number/2);
- + if(codec == NULL)
- + {
- + printk("codec = null\n");
- + break;
- + }
- + for (p = buf; p < buf + rt56xx.number/2; p++)
- + rt5640_dsp_write(codec, ¶m);
- + break;
- + case RT_GET_CODEC_DSP_MODE_IOCTL:
- + if(DBG) printk("case RT_GET_CODEC_DSP_MODE_IOCTL\n");
- +
- + *buf = rt5640->dsp_sw;
- + if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * rt56xx.number))
- + goto err;
- + break;
- + default:
- + printk("unsported dsp command\n");
- + break;
- + }
- +
- + kfree(buf);
- + return 0;
- +
- +err:
- + kfree(buf);
- + return -EFAULT;
- +
- +}
- +EXPORT_SYMBOL_GPL(rt56xx_dsp_ioctl_common);
- +#endif
- +
- +#ifdef CONFIG_PM
- +int rt5640_dsp_suspend(struct snd_soc_codec *codec, pm_message_t state)
- +{
- + struct rt5640_dsp_param param;
- + int ret;
- +
- + if (RT5640_VER_C == snd_soc_read(codec, RT5640_VENDOR_ID))
- + return 0;
- +
- + ret = snd_soc_update_bits(codec, RT5640_PWR_DIG2,
- + RT5640_PWR_I2S_DSP, RT5640_PWR_I2S_DSP);
- + if (ret < 0) {
- + dev_err(codec->dev,
- + "Failed to power up DSP IIS interface: %d\n", ret);
- + goto rsm_err;
- + }
- +
- + ret = snd_soc_update_bits(codec, RT5640_DSP_CTRL3,
- + RT5640_DSP_PD_PIN_MASK, RT5640_DSP_PD_PIN_HI);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to power up DSP: %d\n", ret);
- + goto rsm_err;
- + }
- +
- + ret = snd_soc_update_bits(codec, RT5640_DSP_CTRL3,
- + RT5640_DSP_RST_PIN_MASK, RT5640_DSP_RST_PIN_LO);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to reset DSP: %d\n", ret);
- + goto rsm_err;
- + }
- +
- + mdelay(10);
- +
- + ret = snd_soc_update_bits(codec, RT5640_DSP_CTRL3,
- + RT5640_DSP_RST_PIN_MASK, RT5640_DSP_RST_PIN_HI);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to recover DSP: %d\n", ret);
- + goto rsm_err;
- + }
- +
- + param.cmd_fmt = 0x00e0;
- + param.addr = 0x3fd2;
- + param.data = 0x0030;
- + param.cmd = RT5640_DSP_CMD_MW;
- + ret = rt5640_dsp_write(codec, ¶m);
- + if (ret < 0) {
- + dev_err(codec->dev,
- + "Failed to Power up LDO of Dsp: %d\n", ret);
- + goto rsm_err;
- + }
- +
- + ret = snd_soc_update_bits(codec, RT5640_DSP_CTRL3,
- + RT5640_DSP_PD_PIN_MASK, RT5640_DSP_PD_PIN_LO);
- + if (ret < 0) {
- + dev_err(codec->dev, "Failed to power down DSP: %d\n", ret);
- + goto rsm_err;
- + }
- +
- + return 0;
- +
- +rsm_err:
- +
- + return ret;
- +}
- +EXPORT_SYMBOL_GPL(rt5640_dsp_suspend);
- +
- +int rt5640_dsp_resume(struct snd_soc_codec *codec)
- +{
- + return 0;
- +}
- +EXPORT_SYMBOL_GPL(rt5640_dsp_resume);
- +#endif
- +
- diff --git a/sound/soc/codecs/rt5640-dsp.h b/sound/soc/codecs/rt5640-dsp.h
- new file mode 100644
- index 0000000..6616267
- --- /dev/null
- +++ b/sound/soc/codecs/rt5640-dsp.h
- @@ -0,0 +1,44 @@
- +/*
- + * rt5640-dsp.h -- RT5640 ALSA SoC DSP driver
- + *
- + * Copyright 2011 Realtek Microelectronics
- + * Author: Johnny Hsu <johnnyhsu@realtek.com>
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License version 2 as
- + * published by the Free Software Foundation.
- + */
- +
- +#ifndef __RT5640_DSP_H__
- +#define __RT5640_DSP_H__
- +
- +/* Debug String Length */
- +#define RT5640_DSP_REG_DISP_LEN 12
- +
- +enum {
- + RT5640_DSP_DIS,
- + RT5640_DSP_AEC_NS_FENS,
- + RT5640_DSP_HFBF,
- + RT5640_DSP_FFP,
- +};
- +
- +struct rt5640_dsp_param {
- + u16 cmd_fmt;
- + u16 addr;
- + u16 data;
- + u8 cmd;
- +};
- +
- +int rt5640_dsp_probe(struct snd_soc_codec *codec);
- +int do_rt5640_dsp_set_mode(struct snd_soc_codec *codec, int mode);
- +#ifdef RTK_IOCTL
- +int rt56xx_dsp_ioctl_common(struct snd_hwdep *hw, struct file *file,
- + unsigned int cmd, unsigned long arg);
- +#endif
- +#ifdef CONFIG_PM
- +int rt5640_dsp_suspend(struct snd_soc_codec *codec, pm_message_t state);
- +int rt5640_dsp_resume(struct snd_soc_codec *codec);
- +#endif
- +
- +#endif /* __RT5640_DSP_H__ */
- +
- diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
- index e3d0af0..03b5aca 100644
- --- a/sound/soc/codecs/rt5640.c
- +++ b/sound/soc/codecs/rt5640.c
- @@ -3,6 +3,7 @@
- *
- * Copyright 2011 Realtek Semiconductor Corp.
- * Author: Johnny Hsu <johnnyhsu@realtek.com>
- + *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- @@ -23,88 +24,266 @@
- #include <sound/soc-dapm.h>
- #include <sound/initval.h>
- #include <sound/tlv.h>
- +#include <mach/board-grouper-misc.h>
- +#include <mach/pinmux.h>
- +#include "../board.h"
- +#include "../board-grouper.h"
- +
- +#include <linux/input.h>
- +#include <linux/debugfs.h>
- +#include <linux/cdev.h>
- +#include <linux/slab.h>
- +#include <linux/gpio.h>
- +
- +#define RTK_IOCTL
- +#ifdef RTK_IOCTL
- +#include "rt56xx_ioctl.h"
- +#define DBG 1
- +#define VIRTUAL_REG_FOR_MISC_FUNC 0x99
- +#endif
- +#define AUDIO_IOC_MAGIC 0xf7
- +#define AUDIO_CAPTURE_MODE _IOW(AUDIO_IOC_MAGIC, 6,int)
- +#define AUDIO_STRESS_TEST _IOW(AUDIO_IOC_MAGIC, 1,int)
- +#define AUDIO_IOCTL_START_HEAVY (2)
- +#define AUDIO_IOCTL_START_NORMAL (1)
- +#define AUDIO_IOCTL_STOP (0)
- +#define START_NORMAL (HZ/2)
- +#define START_HEAVY (HZ/20)
- +
- +#define INPUT_SOURCE_NORMAL 100
- +#define INPUT_SOURCE_VR 101
- +#define OUTPUT_SOURCE_NORMAL 200
- +#define OUTPUT_SOURCE_VOICE 201
- +#define INPUT_SOURCE_NO_AGC 300
- +#define INPUT_SOURCE_AGC 301
- +#define END_RECORDING 400
- +#define STOP_COMMUNICATION 401
- +#define START_COMMUNICATION 402
- +
- +static int input_source=INPUT_SOURCE_NORMAL;
- +static int output_source=OUTPUT_SOURCE_NORMAL;
- +static int input_agc = INPUT_SOURCE_NO_AGC;
- +
- +static int poll_rate = 0;
- +static struct delayed_work poll_audio_work;
- +static int count_base = 1;
- +static int count_100 = 0;
- +static int hp_amp_count = 0;
- #include "rt5640.h"
- -#if (CONFIG_SND_SOC_RT5642_MODULE | CONFIG_SND_SOC_RT5642)
- +#if defined(CONFIG_SND_SOC_RT5642_MODULE) || defined(CONFIG_SND_SOC_RT5642)
- #include "rt5640-dsp.h"
- #endif
- -#define RT5640_DEMO 1
- -#define RT5640_REG_RW 1
- -#define RT5640_DET_EXT_MIC 0
- +#define RT5640_REG_RW 1 /* for debug */
- +struct snd_soc_codec *rt5640_audio_codec = NULL;
- +EXPORT_SYMBOL(rt5640_audio_codec);
- +static struct rt5640_priv *rt5640_dsp = NULL;
- -#ifdef RT5640_DEMO
- struct rt5640_init_reg {
- u8 reg;
- u16 val;
- };
- static struct rt5640_init_reg init_list[] = {
- - {RT5640_DUMMY1 , 0x3701},/*fa[12:13] = 1'b;fa[8~10]=1;fa[0]=1*/
- - {RT5640_DEPOP_M1 , 0x0019},/* 8e[4:3] = 11'b; 8e[0] = 1'b */
- - {RT5640_DEPOP_M2 , 0x3100},/* 8f[13] = 1'b */
- - {RT5640_ADDA_CLK1 , 0x1114},/* 73[2] = 1'b */
- - {RT5640_MICBIAS , 0x3030},/* 93[5:4] = 11'b */
- - {RT5640_PRIV_INDEX , 0x003d},/* PR3d[12] = 1'b */
- - {RT5640_PRIV_DATA , 0x3600},
- - {RT5640_CLS_D_OUT , 0xa000},/* 8d[11] = 0'b */
- - {RT5640_PRIV_INDEX , 0x001c},/* PR1c = 0D21'h */
- - {RT5640_PRIV_DATA , 0x0D21},
- - {RT5640_PRIV_INDEX , 0x001b},/* PR1B = 0D21'h */
- - {RT5640_PRIV_DATA , 0x0000},
- - {RT5640_PRIV_INDEX , 0x0012},/* PR12 = 0aa8'h */
- + {RT5640_DUMMY1 , 0x3701},//fa[12:13] = 1'b; fa[8~10]=1; fa[0]=1
- + {RT5640_ADDA_CLK1 , 0x1114},//73[2] = 1'b
- + {RT5640_MICBIAS , 0x3030},//93[5:4] = 11'b
- + {RT5640_CLS_D_OUT , 0xa000},//8d[11] = 0'b
- + {RT5640_PRIV_INDEX , 0x003d},//PR3d[12] = 0'b; PR3d[9] = 1'b
- + {RT5640_PRIV_DATA , 0x2600},
- + {RT5640_PRIV_INDEX , 0x0012},//PR12 = 0aa8'h
- {RT5640_PRIV_DATA , 0x0aa8},
- - {RT5640_PRIV_INDEX , 0x0014},/* PR14 = 0aaa'h */
- - {RT5640_PRIV_DATA , 0x0aaa},
- - {RT5640_PRIV_INDEX , 0x0020},/* PR20 = 6110'h */
- - {RT5640_PRIV_DATA , 0x6110},
- - {RT5640_PRIV_INDEX , 0x0021},/* PR21 = e0e0'h */
- - {RT5640_PRIV_DATA , 0xe0e0},
- - {RT5640_PRIV_INDEX , 0x0023},/* PR23 = 1804'h */
- - {RT5640_PRIV_DATA , 0x1804},
- + {RT5640_PRIV_INDEX , 0x0014},//PR14 = 8aaa'h
- + {RT5640_PRIV_DATA , 0x8aaa},
- + {RT5640_PRIV_INDEX , 0x0020},//PR20 = 6115'h
- + {RT5640_PRIV_DATA , 0x6115},
- + {RT5640_PRIV_INDEX , 0x0023},//PR23 = 0804'h
- + {RT5640_PRIV_DATA , 0x0804},
- /*playback*/
- - {RT5640_STO_DAC_MIXER , 0x1414},/*Dig inf 1 -> Sto DAC mixer -> DACL*/
- - {RT5640_OUT_L3_MIXER , 0x01fe},/*DACL1 -> OUTMIXL*/
- - {RT5640_OUT_R3_MIXER , 0x01fe},/*DACR1 -> OUTMIXR */
- - {RT5640_HP_VOL , 0x8888},/* OUTMIX -> HPVOL */
- - {RT5640_HPO_MIXER , 0xc000},/* HPVOL -> HPOLMIX */
- -/* {RT5640_HPO_MIXER , 0xa000},// DAC1 -> HPOLMIX */
- - {RT5640_SPK_L_MIXER , 0x0036},/* DACL1 -> SPKMIXL */
- - {RT5640_SPK_R_MIXER , 0x0036},/* DACR1 -> SPKMIXR */
- - {RT5640_SPK_VOL , 0x8888},/* SPKMIX -> SPKVOL */
- - {RT5640_SPO_L_MIXER , 0xe800},/* SPKVOLL -> SPOLMIX */
- - {RT5640_SPO_R_MIXER , 0x2800},/* SPKVOLR -> SPORMIX */
- -/* {RT5640_SPO_L_MIXER , 0xb800},//DAC -> SPOLMIX */
- -/* {RT5640_SPO_R_MIXER , 0x1800},//DAC -> SPORMIX */
- -/* {RT5640_I2S1_SDP , 0xD000},//change IIS1 and IIS2 */
- + {RT5640_STO_DAC_MIXER , 0x1414},//Dig inf 1 -> Sto DAC mixer -> DACL
- + {RT5640_OUT_L3_MIXER , 0x01fe},//DACL1 -> OUTMIXL
- + {RT5640_OUT_R3_MIXER , 0x01fe},//DACR1 -> OUTMIXR
- + {RT5640_HP_VOL , 0x8888},//OUTMIX -> HPVOL
- + {RT5640_HPO_MIXER , 0xc000},//HPVOL -> HPOLMIX
- +// {RT5640_HPO_MIXER , 0xa000},//DAC1 -> HPOLMIX
- + {RT5640_SPK_L_MIXER , 0x0036},//DACL1 -> SPKMIXL
- + {RT5640_SPK_R_MIXER , 0x0036},//DACR1 -> SPKMIXR
- + {RT5640_SPK_VOL , 0x8a8a},//SPKMIX -> SPKVOL
- + {RT5640_SPO_L_MIXER , 0xe800},//SPKVOLL -> SPOLMIX
- + {RT5640_SPO_R_MIXER , 0x2800},//SPKVOLR -> SPORMIX
- +// {RT5640_SPO_L_MIXER , 0xb800},//DAC -> SPOLMIX
- +// {RT5640_SPO_R_MIXER , 0x1800},//DAC -> SPORMIX
- + {RT5640_I2S1_SDP , 0x8000},//change IIS1 and IIS2
- /*record*/
- - {RT5640_IN1_IN2 , 0x5080},/*IN1 boost 40db & differential mode*/
- - {RT5640_IN3_IN4 , 0x0500},/*IN2 boost 40db & signal ended mode*/
- - {RT5640_REC_L2_MIXER , 0x005f},/* enable Mic1 -> RECMIXL */
- - {RT5640_REC_R2_MIXER , 0x005f},/* enable Mic1 -> RECMIXR */
- -/* {RT5640_REC_L2_MIXER , 0x006f},//Mic2 -> RECMIXL */
- -/* {RT5640_REC_R2_MIXER , 0x006f},//Mic2 -> RECMIXR */
- - {RT5640_STO_ADC_MIXER , 0x3020},/* ADC -> Sto ADC mixer */
- -
- -#if RT5640_DET_EXT_MIC
- + {RT5640_IN1_IN2 , 0x5080},//IN1 boost 40db and differential mode
- + {RT5640_IN3_IN4 , 0x0840},//IN2 boost 52db and differential mode
- +// {RT5640_REC_L2_MIXER , 0x007d},//Mic1 -> RECMIXL
- +// {RT5640_REC_R2_MIXER , 0x007d},//Mic1 -> RECMIXR
- + {RT5640_REC_L2_MIXER , 0x006f},//Mic2 -> RECMIXL
- + {RT5640_REC_R2_MIXER , 0x006f},//Mic2 -> RECMIXR
- + {RT5640_STO_ADC_MIXER , 0x1000},//ADC -> Sto ADC mixer
- +#ifdef RT5640_DET_EXT_MIC
- {RT5640_MICBIAS , 0x3800},/* enable MICBIAS short current */
- {RT5640_GPIO_CTRL1 , 0x8400},/* set GPIO1 to IRQ */
- {RT5640_GPIO_CTRL3 , 0x0004},/* set GPIO1 output */
- {RT5640_IRQ_CTRL2 , 0x8000},/*set MICBIAS short current to IRQ */
- - /*( if sticky set regBE : 8800 ) */
- #endif
- -
- + {RT5640_CHARGE_PUMP , 0x0f00},
- + {RT5640_PRIV_INDEX , 0x0090},
- + {RT5640_PRIV_DATA , 0x2000},
- + {RT5640_PRIV_INDEX , 0x0091},
- + {RT5640_PRIV_DATA , 0x1000},
- + {RT5640_STO_DAC_MIXER , 0x0404},
- + {RT5640_LOUT_MIXER , 0x3000},
- + {RT5640_I2S1_SDP , 0xe000},
- + {RT5640_DSP_PATH2 , 0x0000},
- + {RT5640_PRIV_INDEX , 0x006e},
- + {RT5640_PRIV_DATA , 0x3159},
- };
- #define RT5640_INIT_REG_LEN ARRAY_SIZE(init_list)
- +
- +static void audio_codec_stress(struct work_struct *work __attribute__((unused)))
- +{
- + u16 temp;
- +
- + if((count_base % 2))
- + temp = snd_soc_write(rt5640_audio_codec, RT5640_OUTPUT, 0xCACA); /* write codec register 0x03 to 0xCACA */
- + else
- + temp = snd_soc_write(rt5640_audio_codec, RT5640_OUTPUT, 0xCBCB); /* write codec register 0x03 to 0xCACA */
- +
- + temp = snd_soc_read(rt5640_audio_codec, RT5640_OUTPUT); /* write codec register 0x03 to 0xCACA */
- +
- + if((count_base % 2)){
- + if(temp != 0xCACA)
- + printk("tegra.i2c-4:audio codec rt5642 write fail\n");
- + }else{
- + if(temp != 0xCBCB)
- + printk("tegra.i2c-4:audio codec rt5642 write fail\n");
- + }
- +
- + count_base = count_base+1;
- +
- + if (count_base == 100){
- + count_base = 0;
- + count_100 = count_100 + 1;
- + printk("AUDIO_CODEC: count = %d (* 100), the register 0x03h is %x\n",count_100,temp);
- + }
- +
- + schedule_delayed_work(&poll_audio_work, poll_rate);
- +}
- +
- +int rt5640_conn_mux_path(struct snd_soc_codec *codec,
- + char *widget_name, char *path_name)
- +{
- + struct snd_soc_dapm_context *dapm = &codec->dapm;
- + struct snd_soc_dapm_widget *w;
- + struct snd_soc_dapm_path *path;
- + const struct snd_kcontrol_new *kcontrol;
- + struct soc_enum *em;
- + unsigned int val, mask, bitmask;
- + int i;
- + if (codec == NULL || widget_name == NULL || path_name == NULL)
- + return -EINVAL;
- + list_for_each_entry(w, &dapm->card->widgets, list)
- + {
- + if (!w->name || w->dapm != dapm)
- + continue;
- + if (!(strcmp(w->name, widget_name))) {
- + dev_info(codec->dev, "w->name=%s\n", w->name);
- + list_for_each_entry(path, &w->sources, list_sink)
- + {
- + if (!(strcmp(path->name, path_name)))
- + path->connect = 1;
- + else
- + path->connect = 0;
- + dev_info(codec->dev,
- + "path->name=%s path->connect=%d\n",
- + path->name, path->connect);
- + }
- + break;
- + }
- + }
- + snd_soc_dapm_sync(dapm);
- + kcontrol = &w->kcontrol_news[0];
- + em = (struct soc_enum *)kcontrol->private_value;
- + for (i = 0; i < em->max; i++)
- + if (!(strcmp(path_name, em->texts[i])))
- + break;
- + for (bitmask = 1; bitmask < em->max; bitmask <<= 1)
- + ;
- + val = i << em->shift_l;
- + mask = (bitmask - 1) << em->shift_l;
- + snd_soc_update_bits(codec, em->reg, mask, val);
- + return 0;
- +}
- +EXPORT_SYMBOL(rt5640_conn_mux_path);
- +
- +//*************************************************************************************************
- +//EQ parameter
- +//*************************************************************************************************
- +enum
- +{
- + NORMAL=0,
- + CLUB,
- + DANCE,
- + LIVE,
- + POP,
- + ROCK,
- + OPPO,
- + TREBLE,
- + BASS,
- + NAKASI,
- +};
- +
- +typedef struct _HW_EQ_PRESET
- +{
- + u16 HwEqType;
- + u16 EqValue[22];
- + u16 HwEQCtrl;
- +
- +}HW_EQ_PRESET;
- +
- +
- +static HW_EQ_PRESET HwEq_Preset[]={
- +/* 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7 0xA8 0xA9 0xAA 0xAB 0xAC, 0xAD 0xAE 0xAF 0xB0 0xB1 0xB2 0xB0*/
- + {NORMAL,{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},0x0000},
- + {CLUB ,{0x1C10,0x0000,0xC1CC,0x1E5D,0x0699,0xCD48,0x188D,0x0699,0xC3B6,0x1CD0,0x0699,0x0000,0x0000,0x0000,0x0436,0x0000,0x0000,0x0000,0x0000},0x000E},
- + {DANCE ,{0x1F2C,0x095B,0xC071,0x1F95,0x0616,0xC96E,0x1B11,0xFC91,0xDCF2,0x1194,0xFAF2,0x0000,0x0000,0x0000,0x0436,0x0000,0x0000,0x0000,0x0000},0x000F},
- + {LIVE ,{0x1EB5,0xFCB6,0xC24A,0x1DF8,0x0E7C,0xC883,0x1C10,0x0699,0xDA41,0x1561,0x0295,0x0000,0x0000,0x0000,0x0436,0x0000,0x0000,0x0000,0x0000},0x000F},
- + {POP ,{0x1EB5,0xFCB6,0xC1D4,0x1E5D,0x0E23,0xD92E,0x16E6,0xFCB6,0x0000,0x0969,0xF988,0x0000,0x0000,0x0000,0x0436,0x0000,0x0000,0x0000,0x0000},0x000F},
- + {ROCK ,{0x1EB5,0xFCB6,0xC071,0x1F95,0x0424,0xC30A,0x1D27,0xF900,0x0C5D,0x0FC7,0x0E23,0x0000,0x0000,0x0000,0x0436,0x0000,0x0000,0x0000,0x0000},0x000F},
- + {OPPO ,{0x0000,0x0000,0xCA4A,0x17F8,0x0FEC,0xCA4A,0x17F8,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},0x000F},
- + {TREBLE,{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x188D,0x1699,0x0000,0x0000,0x0000},0x0020},
- + {BASS ,{0x1A43,0x0C00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},0x0001},
- + {NAKASI,{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x1EF8,0x0000,0x1F77,0x00E4,0x1F79},0x0160},
- +};
- +
- +//*************************************************************************************************
- +//*************************************************************************************************
- +
- static int rt5640_reg_init(struct snd_soc_codec *codec)
- {
- int i;
- +
- for (i = 0; i < RT5640_INIT_REG_LEN; i++)
- snd_soc_write(codec, init_list[i].reg, init_list[i].val);
- +
- + return 0;
- +}
- +
- +static int rt5640_index_sync(struct snd_soc_codec *codec)
- +{
- + int i;
- +
- + for (i = 0; i < RT5640_INIT_REG_LEN; i++)
- + if (RT5640_PRIV_INDEX == init_list[i].reg ||
- + RT5640_PRIV_DATA == init_list[i].reg)
- + snd_soc_write(codec, init_list[i].reg,
- + init_list[i].val);
- return 0;
- }
- -#endif
- static const u16 rt5640_reg[RT5640_VENDOR_ID2 + 1] = {
- [RT5640_RESET] = 0x000c,
- @@ -134,7 +313,7 @@ static const u16 rt5640_reg[RT5640_VENDOR_ID2 + 1] = {
- [RT5640_SPO_CLSD_RATIO] = 0x0004,
- [RT5640_MONO_MIXER] = 0xfc00,
- [RT5640_OUT_L3_MIXER] = 0x01ff,
- - [RT5640_OUT_R3_MIXER] = 0x01ff,
- + [RT5640_OUT_R3_MIXER] = 0x01ff,
- [RT5640_LOUT_MIXER] = 0xf000,
- [RT5640_PWR_ANLG1] = 0x00c0,
- [RT5640_I2S1_SDP] = 0x8000,
- @@ -271,6 +450,48 @@ err:
- return ret;
- }
- +//*************************************************************************************************
- +//for EQ function
- +//*************************************************************************************************
- +static void rt5640_update_eqmode(struct snd_soc_codec *codec, int mode)
- +{
- + u16 HwEqIndex=0;
- +
- + if(mode==NORMAL)
- + {
- + /*clear EQ parameter*/
- + for(HwEqIndex=0;HwEqIndex<=0x12;HwEqIndex++)
- + {
- + rt5640_index_write(codec, HwEqIndex+0xA0, HwEq_Preset[mode].EqValue[HwEqIndex]);
- + }
- +
- + snd_soc_update_bits(codec,0xb1,0x007f,0x0000); //disable Hardware LP,BP1,BP2,BP3,HP1,HP2 block Control
- +
- + //rt5640_index_update_bits(codec,0x11,0x8000,0x0000); /*disable EQ block*/
- + snd_soc_update_bits(codec, 0xb0,0x6000,0x6000);
- + snd_soc_update_bits(codec, 0xb0,0x6000,0x0000);
- + }
- + else
- + {
- + //rt5640_index_update_bits(codec,0x11,0x8000,0x8000); /*enable EQ block*/
- +
- + snd_soc_write(codec,0xb1,HwEq_Preset[mode].HwEQCtrl);
- +
- + /*Fill EQ parameter*/
- + for(HwEqIndex=0;HwEqIndex<=0x12;HwEqIndex++)
- + {
- + rt5640_index_write(codec, HwEqIndex+0xA0,HwEq_Preset[mode].EqValue[HwEqIndex]);
- + }
- + //update EQ parameter
- + //snd_soc_update_bits(codec, 0xb0,0xE000,0xE000);
- + //snd_soc_update_bits(codec, 0xb0,0x6000,0x0000); //clean the bits
- + snd_soc_write(codec, 0xb0,0x6000);
- + }
- +}
- +
- +//*************************************************************************************************
- +//*************************************************************************************************
- +
- static int rt5640_volatile_register(
- struct snd_soc_codec *codec, unsigned int reg)
- {
- @@ -419,41 +640,103 @@ static int rt5640_readable_register(
- }
- }
- -int rt5640_headset_detect(struct snd_soc_codec *codec, int jack_insert)
- +static void dc_calibrate(struct snd_soc_codec *codec)
- {
- - int jack_type;
- + unsigned int sclk_src;
- - if (jack_insert) {
- - snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
- - RT5640_PWR_LDO2, RT5640_PWR_LDO2);
- - snd_soc_update_bits(codec, RT5640_PWR_ANLG2,
- - RT5640_PWR_MB1, RT5640_PWR_MB1);
- - snd_soc_update_bits(codec, RT5640_MICBIAS,
- - RT5640_MIC1_OVCD_MASK | RT5640_MIC1_OVTH_MASK |
- - RT5640_PWR_CLK25M_MASK | RT5640_PWR_MB_MASK,
- - RT5640_MIC1_OVCD_EN | RT5640_MIC1_OVTH_600UA |
- - RT5640_PWR_MB_PU | RT5640_PWR_CLK25M_PU);
- - snd_soc_update_bits(codec, RT5640_DUMMY1,
- - 0x1, 0x1);
- - msleep(50);
- - if (snd_soc_read(codec, RT5640_IRQ_CTRL2) & 0x8)
- - jack_type = RT5640_HEADPHO_DET;
- - else
- - jack_type = RT5640_HEADSET_DET;
- - snd_soc_update_bits(codec, RT5640_IRQ_CTRL2,
- - RT5640_MB1_OC_CLR, 0);
- - } else {
- - snd_soc_update_bits(codec, RT5640_MICBIAS,
- - RT5640_MIC1_OVCD_MASK,
- - RT5640_MIC1_OVCD_DIS);
- -
- - jack_type = RT5640_NO_JACK;
- - }
- + sclk_src = snd_soc_read(codec, RT5640_GLB_CLK) &
- + RT5640_SCLK_SRC_MASK;
- +
- + snd_soc_update_bits(codec, RT5640_PWR_ANLG2,
- + RT5640_PWR_MB1, RT5640_PWR_MB1);
- + snd_soc_update_bits(codec, RT5640_DEPOP_M2,
- + RT5640_DEPOP_MASK, RT5640_DEPOP_MAN);
- + snd_soc_update_bits(codec, RT5640_DEPOP_M1,
- + RT5640_HP_CP_MASK | RT5640_HP_SG_MASK | RT5640_HP_CB_MASK,
- + RT5640_HP_CP_PU | RT5640_HP_SG_DIS | RT5640_HP_CB_PU);
- - return jack_type;
- + snd_soc_update_bits(codec, RT5640_GLB_CLK,
- + RT5640_SCLK_SRC_MASK, 0x2 << RT5640_SCLK_SRC_SFT);
- +
- + rt5640_index_write(codec, RT5640_HP_DCC_INT1, 0x9f00);
- + snd_soc_update_bits(codec, RT5640_PWR_ANLG2,
- + RT5640_PWR_MB1, 0);
- + snd_soc_update_bits(codec, RT5640_GLB_CLK,
- + RT5640_SCLK_SRC_MASK, sclk_src);
- }
- -EXPORT_SYMBOL(rt5640_headset_detect);
- +/**
- + * rt5640_conn_mixer_path - connect mixer widget path.
- + * @codec: SoC audio codec device.
- + * @widget_name: widget name.
- + * @path_name: path name.
- + * @turn: enable or disable.
- + *
- + * Make mixer path connected and update register.
- + *
- + * Returns 0 for success or negative error code.
- + */
- +int rt5640_conn_mixer_path(struct snd_soc_codec *codec,
- + char *widget_name, char *path_name, bool turn)
- +{
- + struct snd_soc_dapm_context *dapm = &codec->dapm;
- + struct snd_soc_dapm_widget *w;
- + struct snd_soc_dapm_path *path;
- + const struct snd_kcontrol *kcontrol;
- + struct soc_mixer_control *mc;
- + unsigned int val, mask;
- + int i, update = 0;
- +
- + if (codec == NULL || widget_name == NULL || path_name == NULL)
- + return -EINVAL;
- +
- + list_for_each_entry(w, &dapm->card->widgets, list)
- + {
- + if (!w->name || w->dapm != dapm)
- + continue;
- + if (!(strcmp(w->name, widget_name))) {
- + if (w->id != snd_soc_dapm_mixer)
- + return -EINVAL;
- + dev_info(codec->dev, "w->name=%s\n", w->name);
- + list_for_each_entry(path, &w->sources, list_sink)
- + {
- + if (path->name &&
- + !(strcmp(path->name, path_name))) {
- + path->connect = turn;
- + dev_info(codec->dev,
- + "path->name=%s connect=%d\n",
- + path->name, path->connect);
- + break;
- + }
- + }
- + update = 1;
- + break;
- + }
- + }
- +
- + if (update) {
- + snd_soc_dapm_sync(dapm);
- +
- + kcontrol = w->kcontrols[0];
- + for (i = 0; i < w->num_kcontrols; i++) {
- + if (!strcmp(path_name, w->kcontrol_news[i].name)) {
- + mc = (struct soc_mixer_control *)
- + w->kcontrol_news[i].private_value;
- + mask = (1 << fls(mc->max)) - 1;
- + val = turn;
- + if (mc->invert)
- + val = mc->max - val;
- + mask = mask << mc->shift;
- + val = val << mc->shift;
- + snd_soc_update_bits(codec, mc->reg, mask, val);
- + break;
- + }
- + }
- + }
- +
- + return 0;
- +}
- +EXPORT_SYMBOL(rt5640_conn_mixer_path);
- static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
- static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
- static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
- @@ -556,7 +839,7 @@ static const SOC_ENUM_SINGLE_DECL(
- /* Interface data select */
- static const char *rt5640_data_select[] = {
- - "Normal", "left copy to right", "right copy to left", "Swap"};
- + "Normal", "swap", "left copy to right", "right copy to left"};
- static const SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA,
- RT5640_IF1_DAC_SEL_SFT, rt5640_data_select);
- @@ -595,7 +878,8 @@ static const SOC_ENUM_SINGLE_DECL(rt5640_dmic_enum, 0, 0, rt5640_dmic_mode);
- #define REGVAL_MAX 0xffff
- static unsigned int regctl_addr;
- static int rt5640_regctl_info(struct snd_kcontrol *kcontrol,
- - struct snd_ctl_elem_info *uinfo) {
- + struct snd_ctl_elem_info *uinfo)
- +{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- @@ -617,17 +901,13 @@ static int rt5640_regctl_put(struct snd_kcontrol *kcontrol,
- {
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- regctl_addr = ucontrol->value.integer.value[0];
- - if (ucontrol->value.integer.value[1] <= REGVAL_MAX)
- - snd_soc_write(codec, regctl_addr,
- - ucontrol->value.integer.value[1]);
- + if(ucontrol->value.integer.value[1] <= REGVAL_MAX)
- + snd_soc_write(codec, regctl_addr, ucontrol->value.integer.value[1]);
- return 0;
- }
- #endif
- -#define VOL_RESCALE_MAX_VOL 0x27 /* 39 */
- -#define VOL_RESCALE_MIX_RANGE 0x1F /* 31 */
- -
- static int rt5640_vol_rescale_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
- @@ -636,9 +916,9 @@ static int rt5640_vol_rescale_get(struct snd_kcontrol *kcontrol,
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- unsigned int val = snd_soc_read(codec, mc->reg);
- - ucontrol->value.integer.value[0] = VOL_RESCALE_MAX_VOL -
- + ucontrol->value.integer.value[0] = RT5640_VOL_RSCL_MAX -
- ((val & RT5640_L_VOL_MASK) >> mc->shift);
- - ucontrol->value.integer.value[1] = VOL_RESCALE_MAX_VOL -
- + ucontrol->value.integer.value[1] = RT5640_VOL_RSCL_MAX -
- (val & RT5640_R_VOL_MASK);
- return 0;
- @@ -652,8 +932,8 @@ static int rt5640_vol_rescale_put(struct snd_kcontrol *kcontrol,
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- unsigned int val, val2;
- - val = VOL_RESCALE_MAX_VOL - ucontrol->value.integer.value[0];
- - val2 = VOL_RESCALE_MAX_VOL - ucontrol->value.integer.value[1];
- + val = RT5640_VOL_RSCL_MAX - ucontrol->value.integer.value[0];
- + val2 = RT5640_VOL_RSCL_MAX - ucontrol->value.integer.value[1];
- return snd_soc_update_bits_locked(codec, mc->reg, RT5640_L_VOL_MASK |
- RT5640_R_VOL_MASK, val << mc->shift | val2);
- }
- @@ -661,18 +941,17 @@ static int rt5640_vol_rescale_put(struct snd_kcontrol *kcontrol,
- static const struct snd_kcontrol_new rt5640_snd_controls[] = {
- /* Speaker Output Volume */
- + SOC_DOUBLE("Speaker Playback Switch", RT5640_SPK_VOL,
- + RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
- SOC_DOUBLE_EXT_TLV("Speaker Playback Volume", RT5640_SPK_VOL,
- - RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, VOL_RESCALE_MIX_RANGE, 0,
- + RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, RT5640_VOL_RSCL_RANGE, 0,
- rt5640_vol_rescale_get, rt5640_vol_rescale_put, out_vol_tlv),
- -
- /* Headphone Output Volume */
- SOC_DOUBLE("HP Playback Switch", RT5640_HP_VOL,
- RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
- -
- SOC_DOUBLE_EXT_TLV("HP Playback Volume", RT5640_HP_VOL,
- - RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, VOL_RESCALE_MIX_RANGE, 0,
- + RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, RT5640_VOL_RSCL_RANGE, 0,
- rt5640_vol_rescale_get, rt5640_vol_rescale_put, out_vol_tlv),
- -
- /* OUTPUT Control */
- SOC_DOUBLE("OUT Playback Switch", RT5640_OUTPUT,
- RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
- @@ -721,6 +1000,8 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {
- /* DMIC */
- SOC_ENUM_EXT("DMIC Switch", rt5640_dmic_enum,
- rt5640_dmic_get, rt5640_dmic_put),
- + SOC_ENUM("ADC IF1 SWITCH", rt5640_if1_adc_enum),
- + SOC_ENUM("DAC IF1 SWITCH", rt5640_if1_dac_enum),
- #ifdef RT5640_REG_RW
- {
- @@ -777,7 +1058,7 @@ static int check_sysclk1_source(struct snd_soc_dapm_widget *source,
- val = snd_soc_read(source->codec, RT5640_GLB_CLK);
- val &= RT5640_SCLK_SRC_MASK;
- - if (val == RT5640_SCLK_SRC_PLL1 || val == RT5640_SCLK_SRC_PLL1T)
- + if (val == RT5640_SCLK_SRC_PLL1)
- return 1;
- else
- return 0;
- @@ -1075,9 +1356,8 @@ static const SOC_ENUM_SINGLE_DECL(
- static const struct snd_kcontrol_new rt5640_mono_adc_l1_mux =
- SOC_DAPM_ENUM("Mono ADC1 left source", rt5640_mono_adc_l1_enum);
- -static const char *rt5640_mono_adc_l2_src[] = {
- - "DMIC L1", "DMIC L2", "Mono DAC MIXL"
- -};
- +static const char *rt5640_mono_adc_l2_src[] =
- + {"DMIC L1", "DMIC L2", "Mono DAC MIXL"};
- static const SOC_ENUM_SINGLE_DECL(
- rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER,
- @@ -1095,9 +1375,8 @@ static const SOC_ENUM_SINGLE_DECL(
- static const struct snd_kcontrol_new rt5640_mono_adc_r1_mux =
- SOC_DAPM_ENUM("Mono ADC1 right source", rt5640_mono_adc_r1_enum);
- -static const char *rt5640_mono_adc_r2_src[] = {
- - "DMIC R1", "DMIC R2", "Mono DAC MIXR"
- -};
- +static const char *rt5640_mono_adc_r2_src[] =
- + {"DMIC R1", "DMIC R2", "Mono DAC MIXR"};
- static const SOC_ENUM_SINGLE_DECL(
- rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER,
- @@ -1163,52 +1442,283 @@ static const SOC_ENUM_SINGLE_DECL(
- static const struct snd_kcontrol_new rt5640_sdi_mux =
- SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum);
- -static int spk_event(struct snd_soc_dapm_widget *w,
- +static int mono_adc_mixer_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
- {
- struct snd_soc_codec *codec = w->codec;
- - static unsigned int spkl_out_enable;
- - static unsigned int spkr_out_enable;
- + unsigned int val, mask;
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- - pr_info("spk_event --SND_SOC_DAPM_POST_PMU\n");
- - snd_soc_update_bits(codec, RT5640_PWR_DIG1, 0x0001, 0x0001);
- - rt5640_index_update_bits(codec, 0x1c, 0xf000, 0xf000);
- - /* rt5640_index_write(codec, 0x1c, 0xfd21); */
- + val = snd_soc_read(codec, RT5640_MONO_ADC_MIXER);
- + mask = RT5640_M_MONO_ADC_L1 | RT5640_M_MONO_ADC_L2 |
- + RT5640_M_MONO_ADC_R1 | RT5640_M_MONO_ADC_R2;
- + if ((val & mask) ^ mask)
- + snd_soc_update_bits(codec, RT5640_DUMMY1,
- + RT5640_M_MAMIX_L | RT5640_M_MAMIX_R, 0);
- + break;
- +
- + case SND_SOC_DAPM_POST_PMD:
- + snd_soc_update_bits(codec, RT5640_DUMMY1,
- + RT5640_M_MAMIX_L | RT5640_M_MAMIX_R,
- + RT5640_M_MAMIX_L | RT5640_M_MAMIX_R);
- + break;
- + default:
- + return 0;
- + }
- + return 0;
- +}
- +static int rt5640_adc_event(struct snd_soc_dapm_widget *w,
- + struct snd_kcontrol *kcontrol, int event)
- +{
- + struct snd_soc_codec *codec = w->codec;
- + switch (event) {
- + case SND_SOC_DAPM_POST_PMU:
- + usleep_range(1000, 1500);
- + rt5640_index_update_bits(codec,
- + RT5640_CHOP_DAC_ADC, 0x1000, 0x1000);
- + break;
- + case SND_SOC_DAPM_PRE_PMU:
- + snd_soc_update_bits(codec, RT5640_STO_ADC_MIXER,
- + 0x5040, 0x5040);
- + break;
- + case SND_SOC_DAPM_POST_PMD:
- + rt5640_index_update_bits(codec,
- + RT5640_CHOP_DAC_ADC, 0x1000, 0x0000);
- + break;
- +
- + default:
- + return 0;
- + }
- +
- + return 0;
- +}
- +
- +static int rt5640_spk_event(struct snd_soc_dapm_widget *w,
- + struct snd_kcontrol *kcontrol, int event)
- +{
- + struct snd_soc_codec *codec = w->codec;
- +
- + switch (event) {
- + case SND_SOC_DAPM_POST_PMU:
- + usleep_range(1000, 1500); /* depop delay */
- + snd_soc_update_bits(codec, RT5640_PWR_DIG1,
- + RT5640_PWR_CLS_D, RT5640_PWR_CLS_D);
- + rt5640_index_update_bits(codec,
- + RT5640_CLSD_INT_REG1, 0xf000, 0xf000);
- + /*Enable DRC */
- + snd_soc_update_bits(codec, RT5640_DRC_AGC_1,
- + RT5640_DRC_AGC_P_MASK | RT5640_DRC_AGC_MASK |
- + RT5640_DRC_AGC_UPD,
- + RT5640_DRC_AGC_P_DAC | RT5640_DRC_AGC_EN |
- + RT5640_DRC_AGC_UPD);
- + snd_soc_update_bits(codec, RT5640_DRC_AGC_2,
- + RT5640_DRC_AGC_PRB_MASK,
- + 0x0003);
- + snd_soc_update_bits(codec, RT5640_DRC_AGC_3,
- + RT5640_DRC_AGC_TAR_MASK,
- + 0x0080);
- + snd_soc_update_bits(codec, RT5640_SPK_VOL,
- + RT5640_L_MUTE | RT5640_R_MUTE, 0);
- + rt5640_update_eqmode(codec,NAKASI);
- + break;
- +
- + case SND_SOC_DAPM_PRE_PMD:
- + snd_soc_update_bits(codec, RT5640_SPK_VOL,
- + RT5640_L_MUTE | RT5640_R_MUTE,
- + RT5640_L_MUTE | RT5640_R_MUTE);
- + /*Disable DRC */
- + snd_soc_update_bits(codec, RT5640_DRC_AGC_1,
- + RT5640_DRC_AGC_P_MASK | RT5640_DRC_AGC_MASK |
- + RT5640_DRC_AGC_UPD, RT5640_DRC_AGC_UPD);
- + snd_soc_update_bits(codec, RT5640_DRC_AGC_2,
- + RT5640_DRC_AGC_PRB_MASK,
- + 0x0000);
- + snd_soc_update_bits(codec, RT5640_DRC_AGC_3,
- + RT5640_DRC_AGC_TAR_MASK,
- + 0x0000);
- + rt5640_index_update_bits(codec,
- + RT5640_CLSD_INT_REG1, 0xf000, 0x0000);
- + snd_soc_update_bits(codec, RT5640_PWR_DIG1,
- + RT5640_PWR_CLS_D, 0);
- + rt5640_update_eqmode(codec,NORMAL);
- + break;
- +
- + default:
- + return 0;
- + }
- +
- + return 0;
- +}
- +
- +static void rt5640_pmu_depop(struct snd_soc_codec *codec)
- +{
- + if (hp_amp_count == 0) {
- + /* depop parameters */
- + snd_soc_update_bits(codec, RT5640_DEPOP_M2,
- + RT5640_DEPOP_MASK, RT5640_DEPOP_MAN);
- + snd_soc_update_bits(codec, RT5640_DEPOP_M1,
- + RT5640_HP_CP_MASK | RT5640_HP_SG_MASK |
- + RT5640_HP_CB_MASK,
- + RT5640_HP_CP_PU | RT5640_HP_SG_DIS | RT5640_HP_CB_PU);
- + /* headphone amp power on */
- + snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
- + RT5640_PWR_FV1 | RT5640_PWR_FV2, 0);
- + snd_soc_update_bits(codec, RT5640_PWR_VOL,
- + RT5640_PWR_HV_L | RT5640_PWR_HV_R,
- + RT5640_PWR_HV_L | RT5640_PWR_HV_R);
- + snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
- + RT5640_PWR_HP_L | RT5640_PWR_HP_R | RT5640_PWR_HA,
- + RT5640_PWR_HP_L | RT5640_PWR_HP_R | RT5640_PWR_HA);
- + /* wait for power to be stable to depop */
- + usleep_range(5000, 6000);
- + snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
- + RT5640_PWR_FV1 | RT5640_PWR_FV2,
- + RT5640_PWR_FV1 | RT5640_PWR_FV2);
- + snd_soc_update_bits(codec, RT5640_DEPOP_M1,
- + RT5640_HP_CO_MASK | RT5640_HP_SG_MASK,
- + RT5640_HP_CO_EN | RT5640_HP_SG_EN);
- + /* headphone unmute sequence */
- + snd_soc_update_bits(codec, RT5640_DEPOP_M3,
- + RT5640_CP_FQ1_MASK | RT5640_CP_FQ2_MASK |
- + RT5640_CP_FQ3_MASK,
- + (RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ1_SFT) |
- + (RT5640_CP_FQ_12_KHZ << RT5640_CP_FQ2_SFT) |
- + (RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ3_SFT));
- + rt5640_index_write(codec, RT5640_MAMP_INT_REG2, 0xfc00);
- + snd_soc_update_bits(codec, RT5640_DEPOP_M1,
- + RT5640_SMT_TRIG_MASK, RT5640_SMT_TRIG_EN);
- + snd_soc_update_bits(codec, RT5640_DEPOP_M1,
- + RT5640_RSTN_MASK, RT5640_RSTN_EN);
- + snd_soc_update_bits(codec, RT5640_DEPOP_M1,
- + RT5640_RSTN_MASK | RT5640_HP_L_SMT_MASK |
- + RT5640_HP_R_SMT_MASK,
- + RT5640_RSTN_DIS | RT5640_HP_L_SMT_EN |
- + RT5640_HP_R_SMT_EN);
- + snd_soc_update_bits(codec, RT5640_HP_VOL,
- + RT5640_L_MUTE | RT5640_R_MUTE, 0);
- + usleep_range(40000, 41000);
- + snd_soc_update_bits(codec, RT5640_DEPOP_M1,
- + RT5640_HP_SG_MASK | RT5640_HP_L_SMT_MASK |
- + RT5640_HP_R_SMT_MASK, RT5640_HP_SG_DIS |
- + RT5640_HP_L_SMT_DIS | RT5640_HP_R_SMT_DIS);
- + }
- + hp_amp_count++;
- +}
- +
- +static void rt5640_pmd_depop(struct snd_soc_codec *codec)
- +{
- +
- + if (--hp_amp_count) {
- + hp_amp_count = 0;
- + return;
- + }
- + /* headphone mute sequence */
- + snd_soc_update_bits(codec, RT5640_DEPOP_M3,
- + RT5640_CP_FQ1_MASK | RT5640_CP_FQ2_MASK | RT5640_CP_FQ3_MASK,
- + (RT5640_CP_FQ_96_KHZ << RT5640_CP_FQ1_SFT) |
- + (RT5640_CP_FQ_12_KHZ << RT5640_CP_FQ2_SFT) |
- + (RT5640_CP_FQ_96_KHZ << RT5640_CP_FQ3_SFT));
- + rt5640_index_write(codec, RT5640_MAMP_INT_REG2, 0xfc00);
- + snd_soc_update_bits(codec, RT5640_DEPOP_M1,
- + RT5640_HP_SG_MASK, RT5640_HP_SG_EN);
- + snd_soc_update_bits(codec, RT5640_DEPOP_M1,
- + RT5640_RSTP_MASK, RT5640_RSTP_EN);
- + snd_soc_update_bits(codec, RT5640_DEPOP_M1,
- + RT5640_RSTP_MASK | RT5640_HP_L_SMT_MASK |
- + RT5640_HP_R_SMT_MASK, RT5640_RSTP_DIS |
- + RT5640_HP_L_SMT_EN | RT5640_HP_R_SMT_EN);
- + snd_soc_update_bits(codec, RT5640_HP_VOL,
- + RT5640_L_MUTE | RT5640_R_MUTE, RT5640_L_MUTE | RT5640_R_MUTE);
- + msleep(30);
- + snd_soc_update_bits(codec, RT5640_DEPOP_M1,
- + RT5640_HP_SG_MASK | RT5640_HP_L_SMT_MASK |
- + RT5640_HP_R_SMT_MASK, RT5640_HP_SG_DIS |
- + RT5640_HP_L_SMT_DIS | RT5640_HP_R_SMT_DIS);
- + /* headphone amp power down */
- + snd_soc_update_bits(codec, RT5640_DEPOP_M1,
- + RT5640_SMT_TRIG_MASK | RT5640_HP_CD_PD_MASK |
- + RT5640_HP_CO_MASK | RT5640_HP_CP_MASK |
- + RT5640_HP_SG_MASK | RT5640_HP_CB_MASK,
- + RT5640_SMT_TRIG_DIS | RT5640_HP_CD_PD_EN |
- + RT5640_HP_CO_DIS | RT5640_HP_CP_PD |
- + RT5640_HP_SG_EN | RT5640_HP_CB_PD);
- + snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
- + RT5640_PWR_HP_L | RT5640_PWR_HP_R | RT5640_PWR_HA,
- + 0);
- +}
- +
- +static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
- + struct snd_kcontrol *kcontrol, int event)
- +{
- + struct snd_soc_codec *codec = w->codec;
- + unsigned int val;
- +
- + switch (event) {
- + case SND_SOC_DAPM_POST_PMU:
- + val = snd_soc_read(codec,0xb1);
- + snd_soc_update_bits(codec,0xb1,0x007f,0x0000);
- + rt5640_pmu_depop(codec);
- + snd_soc_write(codec,0xb1,val);
- + snd_soc_write(codec,0xb0,0x6000);
- break;
- case SND_SOC_DAPM_PRE_PMD:
- - pr_info("spk_event --SND_SOC_DAPM_POST_PMD\n");
- - /* rt5640_index_write(codec, 0x1c, 0xfd00); */
- - rt5640_index_update_bits(codec, 0x1c, 0xf000, 0x0000);
- - snd_soc_update_bits(codec, RT5640_PWR_DIG1, 0x0001, 0x0000);
- + rt5640_pmd_depop(codec);
- + break;
- + default:
- + return 0;
- + }
- +
- + return 0;
- +}
- +
- +static int rt5640_mono_event(struct snd_soc_dapm_widget *w,
- + struct snd_kcontrol *kcontrol, int event)
- +{
- + struct snd_soc_codec *codec = w->codec;
- +
- + switch (event) {
- + case SND_SOC_DAPM_POST_PMU:
- + snd_soc_update_bits(codec, RT5640_MONO_OUT,
- + RT5640_L_MUTE, 0);
- + break;
- +
- + case SND_SOC_DAPM_PRE_PMD:
- + snd_soc_update_bits(codec, RT5640_MONO_OUT,
- + RT5640_L_MUTE, RT5640_L_MUTE);
- break;
- default:
- return 0;
- }
- +
- return 0;
- }
- -static int hp_event(struct snd_soc_dapm_widget *w,
- +static int rt5640_lout_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
- {
- struct snd_soc_codec *codec = w->codec;
- - static unsigned int hp_out_enable;
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- - pr_info("hp_event --SND_SOC_DAPM_POST_PMU\n");
- + rt5640_pmu_depop(codec);
- + snd_soc_update_bits(codec, RT5640_OUTPUT,
- + RT5640_L_MUTE | RT5640_R_MUTE, 0);
- break;
- case SND_SOC_DAPM_PRE_PMD:
- - pr_info("hp_event --SND_SOC_DAPM_POST_PMD\n");
- + snd_soc_update_bits(codec, RT5640_OUTPUT,
- + RT5640_L_MUTE | RT5640_R_MUTE,
- + RT5640_L_MUTE | RT5640_R_MUTE);
- + rt5640_pmd_depop(codec);
- break;
- default:
- return 0;
- }
- +
- return 0;
- }
- @@ -1224,11 +1734,11 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
- SND_SOC_DAPM_MICBIAS("micbias2", RT5640_PWR_ANLG2,
- RT5640_PWR_MB2_BIT, 0),
- /* Input Lines */
- -
- SND_SOC_DAPM_INPUT("MIC1"),
- SND_SOC_DAPM_INPUT("MIC2"),
- SND_SOC_DAPM_INPUT("DMIC1"),
- SND_SOC_DAPM_INPUT("DMIC2"),
- +
- SND_SOC_DAPM_INPUT("IN1P"),
- SND_SOC_DAPM_INPUT("IN1N"),
- SND_SOC_DAPM_INPUT("IN2P"),
- @@ -1258,10 +1768,12 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
- SND_SOC_DAPM_MIXER("RECMIXR", RT5640_PWR_MIXER, RT5640_PWR_RM_R_BIT, 0,
- rt5640_rec_r_mix, ARRAY_SIZE(rt5640_rec_r_mix)),
- /* ADCs */
- - SND_SOC_DAPM_ADC("ADC L", NULL, RT5640_PWR_DIG1,
- - RT5640_PWR_ADC_L_BIT, 0),
- - SND_SOC_DAPM_ADC("ADC R", NULL, RT5640_PWR_DIG1,
- - RT5640_PWR_ADC_R_BIT, 0),
- + SND_SOC_DAPM_ADC_E("ADC L", NULL, RT5640_PWR_DIG1,
- + RT5640_PWR_ADC_L_BIT, 0, rt5640_adc_event,
- + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
- + SND_SOC_DAPM_ADC_E("ADC R", NULL, RT5640_PWR_DIG1,
- + RT5640_PWR_ADC_R_BIT, 0, rt5640_adc_event,
- + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
- /* ADC Mux */
- SND_SOC_DAPM_MUX("Stereo ADC L2 Mux", SND_SOC_NOPM, 0, 0,
- &rt5640_sto_adc_l2_mux),
- @@ -1288,13 +1800,14 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
- rt5640_sto_adc_r_mix, ARRAY_SIZE(rt5640_sto_adc_r_mix)),
- SND_SOC_DAPM_SUPPLY("mono left filter", RT5640_PWR_DIG2,
- RT5640_PWR_ADC_MF_L_BIT, 0, NULL, 0),
- - SND_SOC_DAPM_MIXER("Mono ADC MIXL", SND_SOC_NOPM, 0, 0,
- - rt5640_mono_adc_l_mix, ARRAY_SIZE(rt5640_mono_adc_l_mix)),
- + SND_SOC_DAPM_MIXER_E("Mono ADC MIXL", SND_SOC_NOPM, 0, 0,
- + rt5640_mono_adc_l_mix, ARRAY_SIZE(rt5640_mono_adc_l_mix),
- + mono_adc_mixer_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_SUPPLY("mono right filter", RT5640_PWR_DIG2,
- RT5640_PWR_ADC_MF_R_BIT, 0, NULL, 0),
- - SND_SOC_DAPM_MIXER("Mono ADC MIXR", SND_SOC_NOPM, 0, 0,
- - rt5640_mono_adc_r_mix, ARRAY_SIZE(rt5640_mono_adc_r_mix)),
- -
- + SND_SOC_DAPM_MIXER_E("Mono ADC MIXR", SND_SOC_NOPM, 0, 0,
- + rt5640_mono_adc_r_mix, ARRAY_SIZE(rt5640_mono_adc_r_mix),
- + mono_adc_mixer_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
- /* IF2 Mux */
- SND_SOC_DAPM_MUX("IF2 ADC L Mux", SND_SOC_NOPM, 0, 0,
- &rt5640_if2_adc_l_mux),
- @@ -1320,7 +1833,7 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
- SND_SOC_DAPM_PGA("IF2 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("I2S3", RT5640_PWR_DIG1,
- RT5640_PWR_I2S3_BIT, 0, NULL, 0),
- - SND_SOC_DAPM_PGA("IF3 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
- + SND_SOC_DAPM_PGA("IF3 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("IF3 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("IF3 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("IF3 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
- @@ -1369,6 +1882,10 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
- &rt5640_dac_l2_mux),
- SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0,
- &rt5640_dac_r2_mux),
- + SND_SOC_DAPM_PGA("DAC L2 Volume", RT5640_PWR_DIG1,
- + RT5640_PWR_DAC_L2_BIT, 0, NULL, 0),
- + SND_SOC_DAPM_PGA("DAC R2 Volume", RT5640_PWR_DIG1,
- + RT5640_PWR_DAC_R2_BIT, 0, NULL, 0),
- /* DAC Mixer */
- SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
- @@ -1415,11 +1932,10 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
- SND_SOC_DAPM_PGA("HPOVOL R", RT5640_PWR_VOL,
- RT5640_PWR_HV_R_BIT, 0, NULL, 0),
- /* SPO/HPO/LOUT/Mono Mixer */
- - SND_SOC_DAPM_MIXER("SPOL MIX", SND_SOC_NOPM, 0,
- + SND_SOC_DAPM_MIXER("SPOL MIX",SND_SOC_NOPM, 0,
- 0, rt5640_spo_l_mix, ARRAY_SIZE(rt5640_spo_l_mix)),
- SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0,
- 0, rt5640_spo_r_mix, ARRAY_SIZE(rt5640_spo_r_mix)),
- -
- SND_SOC_DAPM_MIXER("HPOL MIX", SND_SOC_NOPM, 0, 0,
- rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),
- SND_SOC_DAPM_MIXER("HPOR MIX", SND_SOC_NOPM, 0, 0,
- @@ -1429,21 +1945,17 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
- SND_SOC_DAPM_MIXER("Mono MIX", RT5640_PWR_ANLG1, RT5640_PWR_MM_BIT, 0,
- rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)),
- - SND_SOC_DAPM_SUPPLY("Improve mono amp drv", RT5640_PWR_ANLG1,
- - RT5640_PWR_MA_BIT, 0, NULL, 0),
- -
- - SND_SOC_DAPM_SUPPLY("Improve HP amp drv", RT5640_PWR_ANLG1,
- - SND_SOC_NOPM, 0, hp_event, SND_SOC_DAPM_PRE_PMD |
- - SND_SOC_DAPM_POST_PMU),
- + SND_SOC_DAPM_PGA_S("HP amp", 1, SND_SOC_NOPM, 0, 0,
- + rt5640_hp_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
- - SND_SOC_DAPM_PGA("HP L amp", RT5640_PWR_ANLG1,
- - RT5640_PWR_HP_L_BIT, 0, NULL, 0),
- + SND_SOC_DAPM_PGA_S("SPK amp", 1, SND_SOC_NOPM, 0, 0,
- + rt5640_spk_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
- - SND_SOC_DAPM_PGA("HP R amp", RT5640_PWR_ANLG1,
- - RT5640_PWR_HP_R_BIT, 0, NULL, 0),
- + SND_SOC_DAPM_PGA_S("LOUT amp", 1, SND_SOC_NOPM, 0, 0,
- + rt5640_lout_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
- - SND_SOC_DAPM_SUPPLY("Improve SPK amp drv", RT5640_PWR_DIG1,
- - SND_SOC_NOPM, 0, spk_event,
- + SND_SOC_DAPM_PGA_S("Mono amp", 1, RT5640_PWR_ANLG1,
- + RT5640_PWR_MA_BIT, 0, rt5640_mono_event,
- SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
- /* Output Lines */
- @@ -1655,28 +2167,30 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
- {"DAC L2 Mux", "IF2", "IF2 DAC L"},
- {"DAC L2 Mux", "IF3", "IF3 DAC L"},
- {"DAC L2 Mux", "Base L/R", "Audio DSP"},
- + {"DAC L2 Volume", NULL, "DAC L2 Mux"},
- {"DAC R2 Mux", "IF2", "IF2 DAC R"},
- {"DAC R2 Mux", "IF3", "IF3 DAC R"},
- + {"DAC R2 Volume", NULL, "DAC R2 Mux"},
- {"Stereo DAC MIXL", "DAC L1 Switch", "DAC MIXL"},
- - {"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
- + {"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Volume"},
- {"Stereo DAC MIXL", "ANC Switch", "ANC"},
- {"Stereo DAC MIXR", "DAC R1 Switch", "DAC MIXR"},
- - {"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
- + {"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Volume"},
- {"Stereo DAC MIXR", "ANC Switch", "ANC"},
- {"Mono DAC MIXL", "DAC L1 Switch", "DAC MIXL"},
- - {"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
- - {"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"},
- + {"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Volume"},
- + {"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Volume"},
- {"Mono DAC MIXR", "DAC R1 Switch", "DAC MIXR"},
- - {"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
- - {"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"},
- + {"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Volume"},
- + {"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Volume"},
- {"DIG MIXL", "DAC L1 Switch", "DAC MIXL"},
- - {"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"},
- + {"DIG MIXL", "DAC L2 Switch", "DAC L2 Volume"},
- {"DIG MIXR", "DAC R1 Switch", "DAC MIXR"},
- - {"DIG MIXR", "DAC R2 Switch", "DAC R2 Mux"},
- + {"DIG MIXR", "DAC R2 Switch", "DAC R2 Volume"},
- {"DAC L1", NULL, "Stereo DAC MIXL"},
- {"DAC L1", NULL, "PLL1", check_sysclk1_source},
- @@ -1749,39 +2263,32 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
- {"Mono MIX", "OUTVOL L Switch", "OUTVOL L"},
- {"Mono MIX", "BST1 Switch", "BST1"},
- - {"HP L amp", NULL, "HPOL MIX"},
- - {"HP R amp", NULL, "HPOR MIX"},
- -
- -/* {"HP L amp", NULL, "Improve HP amp drv"},
- - {"HP R amp", NULL, "Improve HP amp drv"}, */
- -
- - {"SPOLP", NULL, "SPOL MIX"},
- - {"SPOLN", NULL, "SPOL MIX"},
- - {"SPORP", NULL, "SPOR MIX"},
- - {"SPORN", NULL, "SPOR MIX"},
- -
- - {"SPOLP", NULL, "Improve SPK amp drv"},
- - {"SPOLN", NULL, "Improve SPK amp drv"},
- - {"SPORP", NULL, "Improve SPK amp drv"},
- - {"SPORN", NULL, "Improve SPK amp drv"},
- -
- - {"HPOL", NULL, "Improve HP amp drv"},
- - {"HPOR", NULL, "Improve HP amp drv"},
- -
- - {"HPOL", NULL, "HP L amp"},
- - {"HPOR", NULL, "HP R amp"},
- - {"LOUTL", NULL, "LOUT MIX"},
- - {"LOUTR", NULL, "LOUT MIX"},
- - {"MonoP", NULL, "Mono MIX"},
- - {"MonoN", NULL, "Mono MIX"},
- - {"MonoP", NULL, "Improve mono amp drv"},
- + {"SPK amp", NULL, "SPOL MIX"},
- + {"SPK amp", NULL, "SPOR MIX"},
- + {"SPOLP", NULL, "SPK amp"},
- + {"SPOLN", NULL, "SPK amp"},
- + {"SPORP", NULL, "SPK amp"},
- + {"SPORN", NULL, "SPK amp"},
- +
- + {"HP amp", NULL, "HPOL MIX"},
- + {"HP amp", NULL, "HPOR MIX"},
- + {"HPOL", NULL, "HP amp"},
- + {"HPOR", NULL, "HP amp"},
- +
- + {"LOUT amp", NULL, "LOUT MIX"},
- + {"LOUTL", NULL, "LOUT amp"},
- + {"LOUTR", NULL, "LOUT amp"},
- +
- + {"Mono amp", NULL, "Mono MIX"},
- + {"MonoP", NULL, "Mono amp"},
- + {"MonoN", NULL, "Mono amp"},
- };
- static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)
- {
- int ret = 0, val = snd_soc_read(codec, RT5640_I2S1_SDP);
- - if (codec == NULL)
- + if(codec == NULL)
- return -EINVAL;
- val = (val & RT5640_I2S_IF_MASK) >> RT5640_I2S_IF_SFT;
- @@ -1808,9 +2315,8 @@ static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)
- ret |= RT5640_U_IF3;
- break;
- -#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
- - CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
- -
- +#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
- + defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
- case RT5640_AIF3:
- if (val == RT5640_IF_312 || val == RT5640_IF_321)
- ret |= RT5640_U_IF1;
- @@ -1834,7 +2340,7 @@ static int get_clk_info(int sclk, int rate)
- {
- int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
- - if (sclk <= 0 || rate <= 0)
- + if(sclk <= 0 || rate <= 0)
- return -EINVAL;
- rate = rate << 8;
- @@ -1895,7 +2401,7 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
- return -EINVAL;
- }
- if (dai_sel & RT5640_U_IF1) {
- - mask_clk = RT5640_I2S_BCLK_MS1_MASK | RT5640_I2S_PD1_MASK;
- + mask_clk = RT5640_I2S_BCLK_MS1_MASK | RT5640_I2S_PD1_MASK;
- val_clk = bclk_ms << RT5640_I2S_BCLK_MS1_SFT |
- pre_div << RT5640_I2S_PD1_SFT;
- snd_soc_update_bits(codec, RT5640_I2S1_SDP,
- @@ -1910,8 +2416,8 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
- RT5640_I2S_DL_MASK, val_len);
- snd_soc_update_bits(codec, RT5640_ADDA_CLK1, mask_clk, val_clk);
- }
- -#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
- - CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
- +#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
- + defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
- if (dai_sel & RT5640_U_IF3) {
- mask_clk = RT5640_I2S_BCLK_MS3_MASK | RT5640_I2S_PD3_MASK;
- val_clk = bclk_ms << RT5640_I2S_BCLK_MS3_SFT |
- @@ -1973,7 +2479,7 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
- reg_val |= RT5640_I2S_DF_PCM_A;
- break;
- case SND_SOC_DAIFMT_DSP_B:
- - reg_val |= RT5640_I2S_DF_PCM_B;
- + reg_val |= RT5640_I2S_DF_PCM_B;
- break;
- default:
- return -EINVAL;
- @@ -1994,8 +2500,8 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
- RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
- RT5640_I2S_DF_MASK, reg_val);
- }
- -#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
- - CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
- +#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
- + defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
- if (dai_sel & RT5640_U_IF3) {
- snd_soc_update_bits(codec, RT5640_I2S3_SDP,
- RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
- @@ -2022,9 +2528,6 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
- case RT5640_SCLK_S_PLL1:
- reg_val |= RT5640_SCLK_SRC_PLL1;
- break;
- - case RT5640_SCLK_S_PLL1_TK:
- - reg_val |= RT5640_SCLK_SRC_PLL1T;
- - break;
- case RT5640_SCLK_S_RCCLK:
- reg_val |= RT5640_SCLK_SRC_RCCLK;
- break;
- @@ -2038,6 +2541,7 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
- rt5640->sysclk_src = clk_id;
- dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
- +
- return 0;
- }
- @@ -2077,7 +2581,7 @@ static int rt5640_pll_calc(const unsigned int freq_in,
- if (red < red_t) {
- n = n_t;
- m = m_t;
- - if (red == 0)
- + if(red == 0)
- goto code_find;
- red_t = red;
- }
- @@ -2088,7 +2592,7 @@ static int rt5640_pll_calc(const unsigned int freq_in,
- code_find:
- pll_code->m_bp = bypass;
- - pll_code->m_code = m;
- + pll_code->m_code= m;
- pll_code->n_code = n;
- pll_code->k_code = 2;
- return 0;
- @@ -2123,12 +2627,9 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
- break;
- case RT5640_PLL1_S_BCLK1:
- case RT5640_PLL1_S_BCLK2:
- -
- -#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
- - CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
- -
- +#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
- + defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
- case RT5640_PLL1_S_BCLK3:
- -
- #endif
- dai_sel = get_sdp_info(codec, dai->id);
- if (dai_sel < 0) {
- @@ -2163,11 +2664,16 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
- dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=2\n", pll_code.m_bp,
- (pll_code.m_bp ? 0 : pll_code.m_code), pll_code.n_code);
- - snd_soc_write(codec, RT5640_PLL_CTRL1,
- - pll_code.n_code << RT5640_PLL_N_SFT | pll_code.k_code);
- - snd_soc_write(codec, RT5640_PLL_CTRL2,
- - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5640_PLL_M_SFT |
- - pll_code.m_bp << RT5640_PLL_M_BP_SFT);
- + {
- + int val;
- +
- + val = (pll_code.n_code << RT5640_PLL_N_SFT) | pll_code.k_code;
- + snd_soc_write(codec, RT5640_PLL_CTRL1, val);
- +
- + val = (pll_code.m_bp ? 0 : pll_code.m_code) << RT5640_PLL_M_SFT;
- + val |= (pll_code.m_bp << RT5640_PLL_M_BP_SFT);
- + snd_soc_write(codec, RT5640_PLL_CTRL2, val);
- + }
- rt5640->pll_in = freq_in;
- rt5640->pll_out = freq_out;
- @@ -2197,12 +2703,13 @@ static ssize_t rt5640_index_show(struct device *dev,
- cnt += sprintf(buf, "RT5640 index register\n");
- for (i = 0; i < 0xb4; i++) {
- - if (cnt + 9 >= PAGE_SIZE - 1)
- + if (cnt + RT5640_REG_DISP_LEN >= PAGE_SIZE)
- break;
- val = rt5640_index_read(codec, i);
- if (!val)
- continue;
- - cnt += snprintf(buf + cnt, 10, "%02x: %04x\n", i, val);
- + cnt += snprintf(buf + cnt, RT5640_REG_DISP_LEN,
- + "%02x: %04x\n", i, val);
- }
- if (cnt >= PAGE_SIZE)
- @@ -2217,69 +2724,40 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
- {
- switch (level) {
- case SND_SOC_BIAS_ON:
- -#ifdef RT5640_DEMO
- - snd_soc_update_bits(codec, RT5640_SPK_VOL,
- - RT5640_L_MUTE | RT5640_R_MUTE, 0);
- - snd_soc_update_bits(codec, RT5640_HP_VOL,
- - RT5640_L_MUTE | RT5640_R_MUTE, 0);
- break;
- -#endif
- - case SND_SOC_BIAS_PREPARE:
- -#ifdef RT5640_DEMO
- - snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
- - RT5640_PWR_VREF1 | RT5640_PWR_MB |
- - RT5640_PWR_BG | RT5640_PWR_VREF2,
- - RT5640_PWR_VREF1 | RT5640_PWR_MB |
- - RT5640_PWR_BG | RT5640_PWR_VREF2);
- - msleep(100);
- -
- - snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
- - RT5640_PWR_FV1 | RT5640_PWR_FV2,
- - RT5640_PWR_FV1 | RT5640_PWR_FV2);
- + case SND_SOC_BIAS_PREPARE:
- snd_soc_update_bits(codec, RT5640_PWR_ANLG2,
- RT5640_PWR_MB1 | RT5640_PWR_MB2,
- RT5640_PWR_MB1 | RT5640_PWR_MB2);
- -#endif
- break;
- case SND_SOC_BIAS_STANDBY:
- -#ifdef RT5640_DEMO
- - snd_soc_update_bits(codec, RT5640_SPK_VOL, RT5640_L_MUTE |
- - RT5640_R_MUTE, RT5640_L_MUTE | RT5640_R_MUTE);
- - snd_soc_update_bits(codec, RT5640_HP_VOL, RT5640_L_MUTE |
- - RT5640_R_MUTE, RT5640_L_MUTE | RT5640_R_MUTE);
- -
- snd_soc_update_bits(codec, RT5640_PWR_ANLG2,
- - RT5640_PWR_MB1 | RT5640_PWR_MB2,
- - 0);
- -#endif
- + RT5640_PWR_MB1 | RT5640_PWR_MB2, 0);
- if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
- snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
- RT5640_PWR_VREF1 | RT5640_PWR_MB |
- RT5640_PWR_BG | RT5640_PWR_VREF2,
- RT5640_PWR_VREF1 | RT5640_PWR_MB |
- RT5640_PWR_BG | RT5640_PWR_VREF2);
- - msleep(10);
- + /*
- + * wait 10ms to
- + * make 1st and 2nd reference voltages stable
- + */
- + usleep_range(10000, 15000);
- snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
- RT5640_PWR_FV1 | RT5640_PWR_FV2,
- RT5640_PWR_FV1 | RT5640_PWR_FV2);
- codec->cache_only = false;
- snd_soc_cache_sync(codec);
- + rt5640_index_sync(codec);
- }
- break;
- case SND_SOC_BIAS_OFF:
- -#ifdef RT5640_DEMO
- - snd_soc_update_bits(codec, RT5640_SPK_VOL, RT5640_L_MUTE |
- - RT5640_R_MUTE, RT5640_L_MUTE | RT5640_R_MUTE);
- - snd_soc_update_bits(codec, RT5640_HP_VOL, RT5640_L_MUTE |
- - RT5640_R_MUTE, RT5640_L_MUTE | RT5640_R_MUTE);
- - snd_soc_update_bits(codec, RT5640_OUTPUT, RT5640_L_MUTE |
- - RT5640_R_MUTE, RT5640_L_MUTE | RT5640_R_MUTE);
- - snd_soc_update_bits(codec, RT5640_MONO_OUT,
- - RT5640_L_MUTE, RT5640_L_MUTE);
- -#endif
- + snd_soc_write(codec, RT5640_DEPOP_M1, 0x0004);
- + snd_soc_write(codec, RT5640_DEPOP_M2, 0x1100);
- snd_soc_write(codec, RT5640_PWR_DIG1, 0x0000);
- snd_soc_write(codec, RT5640_PWR_DIG2, 0x0000);
- snd_soc_write(codec, RT5640_PWR_VOL, 0x0000);
- @@ -2296,11 +2774,540 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
- return 0;
- }
- +#ifdef RTK_IOCTL
- +int set_drc_agc_enable(struct snd_soc_codec *codec, int enable, int path)
- +{
- + return snd_soc_update_bits(codec, RT5640_DRC_AGC_1,
- + RT5640_DRC_AGC_P_MASK | RT5640_DRC_AGC_MASK | RT5640_DRC_AGC_UPD,
- + enable << RT5640_DRC_AGC_SFT | path << RT5640_DRC_AGC_P_SFT |
- + 1 << RT5640_DRC_AGC_UPD_BIT );
- +}
- +
- +int set_drc_agc_parameters(struct snd_soc_codec *codec, int attack_rate, int sample_rate,
- + int recovery_rate, int limit_level)
- +{
- + int ret;
- +
- + ret = snd_soc_update_bits(codec, RT5640_DRC_AGC_3,
- + RT5640_DRC_AGC_TAR_MASK, limit_level << RT5640_DRC_AGC_TAR_SFT);
- +
- + if (ret < 0)
- + return ret;
- +
- + ret = snd_soc_update_bits(codec, RT5640_DRC_AGC_1,
- + RT5640_DRC_AGC_AR_MASK | RT5640_DRC_AGC_R_MASK |
- + RT5640_DRC_AGC_UPD | RT5640_DRC_AGC_RC_MASK,
- + attack_rate << RT5640_DRC_AGC_AR_SFT |
- + sample_rate << RT5640_DRC_AGC_R_SFT |
- + recovery_rate << RT5640_DRC_AGC_RC_SFT |
- + 1 << RT5640_DRC_AGC_UPD_BIT );
- +
- + return ret;
- +}
- +
- +int set_digital_boost_gain(struct snd_soc_codec *codec, int post_gain, int pre_gain)
- +{
- + int ret;
- +
- + ret = snd_soc_update_bits(codec, RT5640_DRC_AGC_2,
- + RT5640_DRC_AGC_POB_MASK | RT5640_DRC_AGC_PRB_MASK,
- + post_gain << RT5640_DRC_AGC_POB_SFT |
- + pre_gain << RT5640_DRC_AGC_PRB_SFT);
- +
- + if (ret < 0)
- + return ret;
- +
- + ret = snd_soc_update_bits(codec, RT5640_DRC_AGC_1,
- + RT5640_DRC_AGC_UPD, 1 << RT5640_DRC_AGC_UPD_BIT);
- +
- + return ret;
- +}
- +
- +int set_noise_gate(struct snd_soc_codec *codec, int noise_gate_en, int noise_gate_hold_en,
- + int compression_gain, int noise_gate_th)
- +{
- + int ret;
- +
- + ret = snd_soc_update_bits(codec, RT5640_DRC_AGC_3,
- + RT5640_DRC_AGC_NGB_MASK | RT5640_DRC_AGC_NG_SFT |
- + RT5640_DRC_AGC_NGH_MASK | RT5640_DRC_AGC_NGT_MASK,
- + noise_gate_en << RT5640_DRC_AGC_NG_SFT |
- + noise_gate_hold_en << RT5640_DRC_AGC_NGH_SFT |
- + compression_gain << RT5640_DRC_AGC_NGB_SFT |
- + noise_gate_th << RT5640_DRC_AGC_NGT_SFT);
- +
- + if (ret < 0)
- + return ret;
- +
- + ret = snd_soc_update_bits(codec, RT5640_DRC_AGC_1,
- + RT5640_DRC_AGC_UPD, 1 << RT5640_DRC_AGC_UPD_BIT);
- +
- + return ret;
- +}
- +
- +int set_drc_agc_compression(struct snd_soc_codec *codec, int compression_en, int compression_ratio)
- +{
- + int ret;
- +
- + ret = snd_soc_update_bits(codec, RT5640_DRC_AGC_2,
- + RT5640_DRC_AGC_CP_MASK | RT5640_DRC_AGC_CPR_MASK,
- + compression_en << RT5640_DRC_AGC_CP_SFT |
- + compression_ratio << RT5640_DRC_AGC_CPR_SFT);
- +
- + if (ret < 0)
- + return ret;
- +
- + ret = snd_soc_update_bits(codec, RT5640_DRC_AGC_1,
- + RT5640_DRC_AGC_UPD, 1 << RT5640_DRC_AGC_UPD_BIT);
- +
- + return ret;
- +}
- +
- +//flove083011
- +#if defined(CONFIG_SND_HWDEP)
- +#define RT_CE_CODEC_HWDEP_NAME "rt56xx hwdep "
- +
- +static int rt56xx_hwdep_open(struct snd_hwdep *hw, struct file *file)
- +{
- + printk("enter %s\n", __func__);
- + return 0;
- +}
- +
- +static int rt56xx_hwdep_release(struct snd_hwdep *hw, struct file *file)
- +{
- + printk("enter %s\n", __func__);
- + return 0;
- +}
- +
- +
- +static int rt56xx_hwdep_ioctl_common(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
- +{
- + struct rt56xx_cmd rt56xx;
- +#if 0
- + struct rt56xx_reg *buf;
- + struct rt56xx_reg *p;
- +#else
- + //struct rt56xx_arg *buf;
- + int *buf;
- + //struct rt56xx_arg *p;
- + int *p;
- +#endif
- + int mask1 = 0, mask2 = 0;
- +
- +
- + struct rt56xx_cmd __user *_rt56xx =(struct rt56xx_cmd *)arg;
- + struct snd_soc_codec *codec = hw->private_data;
- +
- + if (copy_from_user(&rt56xx, _rt56xx, sizeof(rt56xx))) {
- + printk("copy_from_user faild\n");
- + return -EFAULT;
- + }
- + if(DBG) printk("rt56xx.number=%d\n",rt56xx.number);
- + buf = kmalloc(sizeof(*buf) * rt56xx.number, GFP_KERNEL);
- + if (buf == NULL)
- + return -ENOMEM;
- + if (copy_from_user(buf, rt56xx.buf, sizeof(*buf) * rt56xx.number)) {
- + goto err;
- + }
- +
- + switch (cmd) {
- + case RT_READ_CODEC_REG_IOCTL:
- + if(DBG) printk(" case RT_READ_CODEC_REG_IOCTL\n");
- +
- + for (p = buf; p < buf + rt56xx.number/2; p++)
- + {
- + *(p+rt56xx.number/2) = snd_soc_read(codec, *p);
- + }
- + if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * rt56xx.number))
- + goto err;
- +
- + break;
- + case RT_WRITE_CODEC_REG_IOCTL:
- + if(DBG) printk(" case RT_WRITE_CODEC_REG_IOCTL\n");
- +
- + for (p = buf; p < buf + rt56xx.number/2; p++)
- + snd_soc_write(codec, *p, *(p+rt56xx.number/2));
- + break;
- + case RT_READ_CODEC_INDEX_IOCTL:
- + if(DBG) printk(" case RT_READ_CODEC_INDEX_IOCTL\n");
- +
- + for (p = buf; p < buf + rt56xx.number/2; p++)
- + {
- + *(p+rt56xx.number/2) = rt5640_index_read(codec, *p);
- + }
- + if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * rt56xx.number))
- + goto err;
- +
- + break;
- + case RT_WRITE_CODEC_INDEX_IOCTL:
- + if(DBG) printk(" case RT_WRITE_CODEC_INDEX_IOCTL\n");
- +
- + for (p = buf; p < buf + rt56xx.number/2; p++)
- + rt5640_index_write(codec, *p, *(p+rt56xx.number/2));
- + break;
- + case RT_SET_CODEC_HWEQ_IOCTL: {
- + u16 virtual_reg;
- + int rt5640_eq_mode;
- +
- + printk(" case RT_SET_CODEC_HWEQ_IOCTL\n");
- +
- + virtual_reg = snd_soc_read(codec, VIRTUAL_REG_FOR_MISC_FUNC);
- + rt5640_eq_mode=(virtual_reg&0x00f0)>>4;
- +
- + if ( rt5640_eq_mode == *buf)
- + break;
- +
- + rt5640_update_eqmode(codec, *buf);
- +
- + virtual_reg &= 0xff0f;
- + virtual_reg |= (*buf<<4);
- + snd_soc_write(codec, VIRTUAL_REG_FOR_MISC_FUNC, virtual_reg);
- + }
- + break;
- + case RT_GET_CODEC_ID:
- + if(DBG) printk(" case RT_GET_CODEC_ID\n");
- +
- + *buf = snd_soc_read(codec, RT5640_VENDOR_ID2);
- +
- + if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * rt56xx.number))
- + goto err;
- +
- + break;
- + case RT_SET_CODEC_SPK_VOL_IOCTL:
- + if(DBG) printk("case RT_SET_CODEC_SPK_VOL_IOCTL\n");
- + snd_soc_update_bits(codec, RT5640_SPK_VOL,
- + RT5640_L_VOL_MASK | RT5640_R_VOL_MASK,
- + *(buf)<<RT5640_L_VOL_SFT | *(buf)<<RT5640_R_VOL_SFT);
- + break;
- + case RT_SET_CODEC_MIC_GAIN_IOCTL:
- + if(DBG) printk("case RT_SET_CODEC_MIC_GAIN_IOCTL\n");
- + snd_soc_update_bits(codec, RT5640_IN1_IN2,
- + RT5640_BST_MASK1,
- + *(buf)<<RT5640_BST_SFT1);
- + snd_soc_update_bits(codec, RT5640_IN3_IN4,
- + RT5640_BST_MASK2,
- + *(buf)<<RT5640_BST_SFT2);
- + break;
- + case RT_SET_CODEC_3D_SPK_IOCTL:
- + if(DBG) printk("case RT_SET_CODEC_3D_SPK_IOCTL\n");
- +
- + if(rt56xx.number < 4)
- + break;
- + mask1 = 0;
- + if(*buf != -1)
- + mask1 |= RT5640_3D_SPK_MASK;
- + if(*(buf+1) != -1)
- + mask1 |= RT5640_3D_SPK_M_MASK;
- + if(*(buf+2) != -1)
- + mask1 |= RT5640_3D_SPK_CG_MASK;
- + if(*(buf+3) != -1)
- + mask1 |= RT5640_3D_SPK_SG_MASK;
- +
- + rt5640_index_update_bits(codec, RT5640_3D_SPK, mask1,
- + *(buf)<<RT5640_3D_SPK_SFT | *(buf+1)<<RT5640_3D_SPK_M_SFT |
- + *(buf+2)<<RT5640_3D_SPK_CG_SFT | *(buf+3)<<RT5640_3D_SPK_SG_SFT);
- + break;
- + case RT_SET_CODEC_MP3PLUS_IOCTL:
- + if(DBG) printk("case RT_SET_CODEC_MP3PLUS_IOCTL\n");
- +
- + if(rt56xx.number < 5)
- + break;
- + mask1 = mask2 = 0;
- + if(*buf != -1)
- + mask1 |= RT5640_M_MP3_MASK;
- + if(*(buf+1) != -1)
- + mask1 |= RT5640_EG_MP3_MASK;
- + if(*(buf+2) != -1)
- + mask2 |= RT5640_OG_MP3_MASK;
- + if(*(buf+3) != -1)
- + mask2 |= RT5640_HG_MP3_MASK;
- + if(*(buf+4) != -1)
- + mask2 |= RT5640_MP3_WT_MASK;
- +
- + snd_soc_update_bits(codec, RT5640_MP3_PLUS1, mask1,
- + *(buf)<<RT5640_M_MP3_SFT | *(buf+1)<<RT5640_EG_MP3_SFT);
- +
- +
- + snd_soc_update_bits(codec, RT5640_MP3_PLUS2, mask2,
- + *(buf+2)<<RT5640_OG_MP3_SFT | *(buf+3)<<RT5640_HG_MP3_SFT |
- + *(buf+4)<<RT5640_MP3_WT_SFT);
- + break;
- + case RT_SET_CODEC_3D_HEADPHONE_IOCTL:
- + if(DBG) printk("case RT_SET_CODEC_3D_HEADPHONE_IOCTL\n");
- +
- + if(rt56xx.number < 4)
- + break;
- + mask1 = 0;
- + if(*buf != -1)
- + mask1 |= RT5640_3D_HP_MASK;
- + if(*(buf+1) != -1)
- + mask1 |= RT5640_3D_BT_MASK;
- + if(*(buf+2) != -1)
- + mask1 |= RT5640_3D_1F_MIX_MASK;
- + if(*(buf+3) != -1)
- + mask1 |= RT5640_3D_HP_M_MASK;
- +
- + snd_soc_update_bits(codec, RT5640_3D_HP, mask1,
- + *(buf)<<RT5640_3D_HP_SFT | *(buf+1)<<RT5640_3D_BT_SFT |
- + *(buf+2)<<RT5640_3D_1F_MIX_SFT | *(buf+3)<<RT5640_3D_HP_M_SFT);
- +
- + if(*(buf+4) != -1)
- + rt5640_index_update_bits(codec, 0x59, 0x1f, *(buf+4) );
- + break;
- + case RT_SET_CODEC_BASS_BACK_IOCTL:
- + if(DBG) printk("case RT_SET_CODEC_BASSBACK_IOCTL\n");
- +
- + if(rt56xx.number < 3)
- + break;
- + mask1 = 0;
- + if(*buf != -1)
- + mask1 |= RT5640_BB_MASK;
- + if(*(buf+1) != -1)
- + mask1 |= RT5640_BB_CT_MASK;
- + if(*(buf+2) != -1)
- + mask1 |= RT5640_G_BB_BST_MASK;
- +
- + snd_soc_update_bits(codec, RT5640_BASE_BACK, mask1,
- + *(buf)<<RT5640_BB_SFT | *(buf+1)<<RT5640_BB_CT_SFT |
- + *(buf+2)<<RT5640_G_BB_BST_SFT );
- + break;
- + case RT_SET_CODEC_DIPOLE_SPK_IOCTL:
- + if(DBG) printk("case RT_SET_CODEC_DIPOLE_SPK_IOCTL\n");
- +
- + if(rt56xx.number < 2)
- + break;
- + mask1 = 0;
- + if(*buf != -1)
- + mask1 |= RT5640_DP_SPK_MASK;
- + if(*(buf+1) != -1)
- + mask1 |= RT5640_DP_ATT_MASK;
- +
- + rt5640_index_update_bits(codec, RT5640_DIP_SPK_INF, mask1,
- + *(buf)<<RT5640_DP_SPK_SFT | *(buf+1)<<RT5640_DP_ATT_SFT );
- + break;
- + case RT_SET_CODEC_DRC_AGC_ENABLE_IOCTL:
- + if(DBG) printk("case RT_SET_CODEC_DRC_AGC_ENABLE_IOCTL\n");
- +
- + if(rt56xx.number < 2)
- + break;
- + set_drc_agc_enable(codec, *(buf), *(buf+1));
- + break;
- + case RT_SET_CODEC_DRC_AGC_PAR_IOCTL:
- + if(DBG) printk("case RT_SET_CODEC_DRC_AGC_PAR_IOCTL\n");
- + if(rt56xx.number < 4)
- + break;
- + set_drc_agc_parameters(codec, *(buf), *(buf+1), *(buf+2), *(buf+3));
- + break;
- + case RT_SET_CODEC_DIGI_BOOST_GAIN_IOCTL:
- + if(DBG) printk("case RT_SET_CODEC_DIGI_BOOST_GAIN_IOCTL\n");
- + if(rt56xx.number < 2)
- + break;
- +
- + set_digital_boost_gain(codec, *(buf), *(buf+1));
- + break;
- + case RT_SET_CODEC_NOISE_GATE_IOCTL:
- + if(DBG) printk("case RT_SET_CODEC_NOISE_GATE_IOCTL\n");
- + if(rt56xx.number < 4)
- + break;
- + set_noise_gate(codec, *(buf), *(buf+1), *(buf+2), *(buf+3));
- + break;
- + case RT_SET_CODEC_DRC_AGC_COMP_IOCTL:
- + if(DBG) printk("case RT_SET_CODEC_DRC_AGC_COMP_IOCTL\n");
- + if(rt56xx.number < 2)
- + break;
- +
- + set_drc_agc_compression(codec, *(buf), *(buf+1));
- + break;
- + case RT_SET_CODEC_WNR_ENABLE_IOCTL:
- + if(DBG) printk("case RT_SET_CODEC_WNR_ENABLE_IOCTL\n");
- +
- + rt5640_index_update_bits(codec, RT5640_WND_1, RT5640_WND_MASK,
- + *(buf)<<RT5640_WND_SFT );
- + break;
- + case RT_SET_CODEC_DSP_MODE_IOCTL:
- + if(DBG) printk("case RT_SET_CODEC_DSP_MODE_IOCTL\n");
- + do_rt5640_dsp_set_mode(codec,*(buf));
- + break;
- +
- + case RT_GET_CODEC_HWEQ_IOCTL:
- + case RT_GET_CODEC_SPK_VOL_IOCTL:
- + case RT_GET_CODEC_MIC_GAIN_IOCTL:
- + case RT_GET_CODEC_3D_SPK_IOCTL:
- + case RT_GET_CODEC_MP3PLUS_IOCTL:
- + case RT_GET_CODEC_3D_HEADPHONE_IOCTL:
- + case RT_GET_CODEC_BASS_BACK_IOCTL:
- + case RT_GET_CODEC_DIPOLE_SPK_IOCTL:
- + case RT_GET_CODEC_DIGI_BOOST_GAIN_IOCTL:
- + case RT_GET_CODEC_NOISE_GATE_IOCTL:
- + case RT_GET_CODEC_DRC_AGC_COMP_IOCTL:
- + default:
- + printk("default\n");
- + break;
- + }
- +
- + kfree(buf);
- + return 0;
- +
- +err:
- + kfree(buf);
- + return -EFAULT;
- +
- +}
- +
- +static int rt56xx_codec_dump_reg(struct snd_hwdep *hw, struct file *file, unsigned long arg)
- +{
- + struct rt56xx_cmd rt56xx;
- + struct rt56xx_cmd __user *_rt56xx =(struct rt56xx_cmd *)arg;
- + int *buf;
- + struct snd_soc_codec *codec = hw->private_data;
- + int number = RT5640_VENDOR_ID2 + 1;
- + int i;
- +
- + printk(KERN_DEBUG "enter %s, number = %d\n", __func__, number);
- + if (copy_from_user(&rt56xx, _rt56xx, sizeof(rt56xx)))
- + return -EFAULT;
- +
- + buf = kmalloc(sizeof(*buf) * number, GFP_KERNEL);
- + if (buf == NULL)
- + return -ENOMEM;
- +
- + for (i = 0; i < number/2; i++)
- + {
- + buf[i] = i << 1;
- + buf[i+number/2] = codec->read(codec, buf[i]);
- + }
- + if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * i))
- + goto err;
- + rt56xx.number = number;
- + if (copy_to_user(_rt56xx, &rt56xx, sizeof(rt56xx)))
- + goto err;
- + kfree(buf);
- + return 0;
- +err:
- + kfree(buf);
- + return -EFAULT;
- +
- +}
- +
- +static int rt56xx_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
- +{
- +
- + printk("***********************rt56xx_hwdep_ioctl cmd=%x,arg=%lx**********************\n",cmd,arg);
- +#if 0
- + if (cmd == RT_READ_ALL_CODEC_REG_IOCTL)
- + {
- + return rt56xx_codec_dump_reg(hw, file, arg);
- + }
- + else
- + {
- + return rt56xx_hwdep_ioctl_common(hw, file, cmd, arg);
- + }
- +#else
- + switch (cmd) {
- + case RT_READ_ALL_CODEC_REG_IOCTL:
- + return rt56xx_codec_dump_reg(hw, file, arg);
- + case AUDIO_CAPTURE_MODE:
- + switch(arg){
- + case INPUT_SOURCE_NORMAL:
- + case INPUT_SOURCE_VR:
- + printk("AUDIO_CODEC: Capture mode [%s]\n",
- + arg == INPUT_SOURCE_NORMAL ? "NORMAL" : "VR");
- + input_source=arg;
- + if(arg == INPUT_SOURCE_VR){
- + do_rt5640_dsp_set_mode(rt5640_audio_codec,RT5640_DSP_AEC_NS_FENS);
- + }else{
- + do_rt5640_dsp_set_mode(rt5640_audio_codec,RT5640_DSP_DIS);
- + }
- + break;
- + case INPUT_SOURCE_AGC:
- + case INPUT_SOURCE_NO_AGC:
- + printk("AUDIO_CODEC: Capture mode [%s]\n",
- + arg == INPUT_SOURCE_AGC ? "AGC" : "NON-AGC");
- + input_agc = arg;
- + if(arg == INPUT_SOURCE_AGC){
- + do_rt5640_dsp_set_mode(rt5640_audio_codec,RT5640_DSP_AEC_NS_FENS);
- + }else{
- + do_rt5640_dsp_set_mode(rt5640_audio_codec,RT5640_DSP_DIS);
- + }
- + break;
- + case OUTPUT_SOURCE_NORMAL:
- + case OUTPUT_SOURCE_VOICE:
- + printk("AUDIO_CODEC: Capture mode [%s]\n",
- + arg == OUTPUT_SOURCE_NORMAL ? "NORMAL" : "VOICE");
- + output_source=arg;
- + if(arg == OUTPUT_SOURCE_VOICE){
- + do_rt5640_dsp_set_mode(rt5640_audio_codec,RT5640_DSP_AEC_NS_FENS);
- + }
- + break;
- + case END_RECORDING:
- + do_rt5640_dsp_set_mode(rt5640_audio_codec,RT5640_DSP_DIS);
- + break;
- + case START_COMMUNICATION:
- + printk("AUDIO_CODEC: Capture mode [%s]\n",
- + arg == START_COMMUNICATION ? "COMMUNICATION" : "NORMAL");
- + if(arg == START_COMMUNICATION){
- + do_rt5640_dsp_set_mode(rt5640_audio_codec,RT5640_DSP_AEC_NS_FENS);
- + }
- + break;
- + case STOP_COMMUNICATION:
- + do_rt5640_dsp_set_mode(rt5640_audio_codec,RT5640_DSP_DIS);
- + break;
- + default:
- + break;
- + }
- + break;
- + case AUDIO_STRESS_TEST:
- + printk("AUDIO_CODEC: AUDIO_STRESS_TEST: %lu (1: Start, 0: Stop)\n",arg);
- + if(arg==AUDIO_IOCTL_START_HEAVY){
- + poll_rate = START_HEAVY;
- + schedule_delayed_work(&poll_audio_work, poll_rate);
- + }else if(arg==AUDIO_IOCTL_START_NORMAL){
- + poll_rate = START_NORMAL;
- + schedule_delayed_work(&poll_audio_work,poll_rate);
- + }else if(arg==AUDIO_IOCTL_STOP){
- + cancel_delayed_work_sync(&poll_audio_work);
- + }
- +
- + break;
- +#if defined(CONFIG_SND_SOC_RT5642_MODULE) || defined(CONFIG_SND_SOC_RT5642)
- + case RT_READ_CODEC_DSP_IOCTL:
- + case RT_WRITE_CODEC_DSP_IOCTL:
- + case RT_GET_CODEC_DSP_MODE_IOCTL:
- + return rt56xx_dsp_ioctl_common(hw, file, cmd, arg);
- +#endif
- + default:
- + return rt56xx_hwdep_ioctl_common(hw, file, cmd, arg);
- +#endif
- + }
- +
- + return -EINVAL;
- +}
- +
- +static int realtek_ce_init_hwdep(struct snd_soc_codec *codec)
- +{
- + struct snd_hwdep *hw;
- + struct snd_card *card = codec->card->snd_card;
- + int err;
- +
- + if ((err = snd_hwdep_new(card, RT_CE_CODEC_HWDEP_NAME, 0, &hw)) < 0)
- + return err;
- +
- + strcpy(hw->name, RT_CE_CODEC_HWDEP_NAME);
- + hw->private_data = codec;
- + hw->ops.open = rt56xx_hwdep_open;
- + hw->ops.release = rt56xx_hwdep_release;
- + hw->ops.ioctl = rt56xx_hwdep_ioctl;
- + return 0;
- +}
- +#endif
- +#endif
- +
- static int rt5640_probe(struct snd_soc_codec *codec)
- {
- struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
- int ret;
- - u16 val;
- +
- + codec->dapm.idle_bias_off = 1;
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
- if (ret != 0) {
- @@ -2308,20 +3315,14 @@ static int rt5640_probe(struct snd_soc_codec *codec)
- return ret;
- }
- - val = snd_soc_read(codec, RT5640_RESET);
- - if (val != rt5640_reg[RT5640_RESET]) {
- - dev_err(codec->dev,
- - "Device with ID register %x is not a rt5640\n", val);
- - return -ENODEV;
- - }
- -
- rt5640_reset(codec);
- snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
- RT5640_PWR_VREF1 | RT5640_PWR_MB |
- RT5640_PWR_BG | RT5640_PWR_VREF2,
- RT5640_PWR_VREF1 | RT5640_PWR_MB |
- RT5640_PWR_BG | RT5640_PWR_VREF2);
- - msleep(100);
- + /* need wait 10ms to make 1st and 2nd reference voltage stable */
- + usleep_range(10000, 15000);
- snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
- RT5640_PWR_FV1 | RT5640_PWR_FV2,
- RT5640_PWR_FV1 | RT5640_PWR_FV2);
- @@ -2340,21 +3341,14 @@ static int rt5640_probe(struct snd_soc_codec *codec)
- RT5640_DMIC_2L_LH_FALLING | RT5640_DMIC_2R_LH_RISING);
- }
- -#ifdef RT5640_DEMO
- rt5640_reg_init(codec);
- -#endif
- -
- -
- -#if (CONFIG_SND_SOC_RT5642_MODULE | CONFIG_SND_SOC_RT5642)
- - rt5640_register_dsp(codec);
- -#endif
- -
- + dc_calibrate(codec);
- codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
- -
- - snd_soc_add_controls(codec, rt5640_snd_controls,
- - ARRAY_SIZE(rt5640_snd_controls));
- -
- rt5640->codec = codec;
- + rt5640_audio_codec = codec;
- + rt5640_dsp = rt5640;
- + rt5640->dsp_sw = RT5640_DSP_AEC_NS_FENS;
- +
- ret = device_create_file(codec->dev, &dev_attr_index_reg);
- if (ret != 0) {
- dev_err(codec->dev,
- @@ -2362,30 +3356,73 @@ static int rt5640_probe(struct snd_soc_codec *codec)
- return ret;
- }
- + snd_soc_add_controls(codec, rt5640_snd_controls,ARRAY_SIZE(rt5640_snd_controls));
- + snd_soc_dapm_new_controls(&codec->dapm, rt5640_dapm_widgets,
- + ARRAY_SIZE(rt5640_dapm_widgets));
- + snd_soc_dapm_add_routes(&codec->dapm, rt5640_dapm_routes,
- + ARRAY_SIZE(rt5640_dapm_routes));
- +#if defined(CONFIG_SND_SOC_RT5642_MODULE) || defined(CONFIG_SND_SOC_RT5642)
- + rt5640_dsp_probe(codec);
- +#endif
- +
- +#ifdef RTK_IOCTL
- +#if defined(CONFIG_SND_HWDEP)
- + printk("************************realtek_ce_init_hwdep*************************************\n");
- + realtek_ce_init_hwdep(codec);
- +#endif
- +#endif
- + do_rt5640_dsp_set_mode(rt5640_audio_codec,RT5640_DSP_DIS);
- return 0;
- }
- static int rt5640_remove(struct snd_soc_codec *codec)
- {
- rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
- - rt5640_reset(codec);
- - snd_soc_write(codec, RT5640_PWR_ANLG1, 0);
- -
- return 0;
- }
- +
- #ifdef CONFIG_PM
- static int rt5640_suspend(struct snd_soc_codec *codec, pm_message_t state)
- {
- - rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
- - snd_soc_write(codec, RT5640_PWR_ANLG1, 0);
- + int ret =0;
- + printk("rt5640_suspend+\n");
- +#if defined(CONFIG_SND_SOC_RT5642_MODULE) || defined(CONFIG_SND_SOC_RT5642)
- + /* After opening LDO of DSP, then close LDO of codec.
- + * (1) DSP LDO power on
- + * (2) DSP core power off
- + * (3) DSP IIS interface power off
- + * (4) Toggle pin of codec LDO1 to power off
- + */
- + rt5640_dsp_suspend(codec, state);
- +#endif
- + snd_soc_update_bits(codec, RT5640_SPK_VOL,
- + RT5640_L_MUTE | RT5640_R_MUTE,
- + RT5640_L_MUTE | RT5640_R_MUTE);
- + rt5640_index_update_bits(codec,
- + RT5640_CLSD_INT_REG1, 0xf000, 0x0000);
- + rt5640_pmd_depop(codec);
- + rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
- + tegra_gpio_enable(TEGRA_GPIO_PW4);
- + ret = gpio_request(TEGRA_GPIO_PW4, "audio_mclk");
- + if (ret < 0)
- + pr_err("%s: gpio_request failed for gpio %s\n",__func__, "AUDIO_MCLK");
- + gpio_direction_output(TEGRA_GPIO_PW4, 0);
- + gpio_free(TEGRA_GPIO_PW4);
- + printk("rt5640_suspend-\n");
- return 0;
- }
- static int rt5640_resume(struct snd_soc_codec *codec)
- {
- + printk("rt5640_resume+\n");
- + tegra_gpio_disable(TEGRA_GPIO_PW4);
- rt5640_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- -
- +#if defined(CONFIG_SND_SOC_RT5642_MODULE) || defined(CONFIG_SND_SOC_RT5642)
- + /* After opening LDO of codec, then close LDO of DSP. */
- + rt5640_dsp_resume(codec);
- +#endif
- + printk("rt5640_resume-\n");
- return 0;
- }
- #else
- @@ -2444,8 +3481,8 @@ struct snd_soc_dai_driver rt5640_dai[] = {
- },
- .ops = &rt5640_aif_dai_ops,
- },
- -#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
- - CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
- +#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
- + defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
- {
- .name = "rt5640-aif3",
- .id = RT5640_AIF3,
- @@ -2480,10 +3517,12 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5640 = {
- .volatile_register = rt5640_volatile_register,
- .readable_register = rt5640_readable_register,
- .reg_cache_step = 1,
- - .dapm_widgets = rt5640_dapm_widgets,
- - .num_dapm_widgets = ARRAY_SIZE(rt5640_dapm_widgets),
- - .dapm_routes = rt5640_dapm_routes,
- - .num_dapm_routes = ARRAY_SIZE(rt5640_dapm_routes),
- + //.controls = rt5640_snd_controls,
- + //.num_controls = ARRAY_SIZE(rt5640_snd_controls),
- + //.dapm_widgets = rt5640_dapm_widgets,
- + //.num_dapm_widgets = ARRAY_SIZE(rt5640_dapm_widgets),
- + //.dapm_routes = rt5640_dapm_routes,
- + //.num_dapm_routes = ARRAY_SIZE(rt5640_dapm_routes),
- };
- static const struct i2c_device_id rt5640_i2c_id[] = {
- @@ -2492,12 +3531,14 @@ static const struct i2c_device_id rt5640_i2c_id[] = {
- };
- MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id);
- -static int rt5640_i2c_probe(struct i2c_client *i2c,
- +static int __devinit rt5640_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
- {
- struct rt5640_priv *rt5640;
- int ret;
- + printk("%s\n", __func__);
- +
- rt5640 = kzalloc(sizeof(struct rt5640_priv), GFP_KERNEL);
- if (NULL == rt5640)
- return -ENOMEM;
- @@ -2508,17 +3549,29 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
- rt5640_dai, ARRAY_SIZE(rt5640_dai));
- if (ret < 0)
- kfree(rt5640);
- + INIT_DELAYED_WORK(&poll_audio_work, audio_codec_stress);
- return ret;
- }
- -static __devexit int rt5640_i2c_remove(struct i2c_client *i2c)
- +static int __devexit rt5640_i2c_remove(struct i2c_client *i2c)
- {
- snd_soc_unregister_codec(&i2c->dev);
- kfree(i2c_get_clientdata(i2c));
- return 0;
- }
- +static void rt5640_i2c_shutdown(struct i2c_client *client)
- +{
- + struct rt5640_priv *rt5640 = i2c_get_clientdata(client);
- + struct snd_soc_codec *codec = rt5640->codec;
- +
- + if (codec != NULL)
- + rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
- +
- + return;
- +}
- +
- struct i2c_driver rt5640_i2c_driver = {
- .driver = {
- .name = "rt5640",
- @@ -2526,11 +3579,13 @@ struct i2c_driver rt5640_i2c_driver = {
- },
- .probe = rt5640_i2c_probe,
- .remove = __devexit_p(rt5640_i2c_remove),
- + .shutdown = rt5640_i2c_shutdown,
- .id_table = rt5640_i2c_id,
- };
- static int __init rt5640_modinit(void)
- {
- + printk("%s\n", __func__);
- return i2c_add_driver(&rt5640_i2c_driver);
- }
- module_init(rt5640_modinit);
- diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
- index d6920f0..7e84c1b 100644
- --- a/sound/soc/codecs/rt5640.h
- +++ b/sound/soc/codecs/rt5640.h
- @@ -144,6 +144,11 @@
- /* Index of Codec Private Register definition */
- +#define RT5640_BIAS_CUR1 0x12
- +#define RT5640_BIAS_CUR3 0x14
- +#define RT5640_CLSD_INT_REG1 0x1c
- +#define RT5640_MAMP_INT_REG2 0x37
- +#define RT5640_CHOP_DAC_ADC 0x3d
- #define RT5640_3D_SPK 0x63
- #define RT5640_WND_1 0x6c
- #define RT5640_WND_2 0x6d
- @@ -152,6 +157,7 @@
- #define RT5640_WND_5 0x70
- #define RT5640_WND_8 0x73
- #define RT5640_DIP_SPK_INF 0x75
- +#define RT5640_HP_DCC_INT1 0x77
- #define RT5640_EQ_BW_LOP 0xa0
- #define RT5640_EQ_GN_LOP 0xa1
- #define RT5640_EQ_FC_BP1 0xa2
- @@ -191,7 +197,9 @@
- /* IN1 and IN2 Control (0x0d) */
- /* IN3 and IN4 Control (0x0e) */
- +#define RT5640_BST_MASK1 (0xf<<12)
- #define RT5640_BST_SFT1 12
- +#define RT5640_BST_MASK2 (0xf<<8)
- #define RT5640_BST_SFT2 8
- #define RT5640_IN_DF1 (0x1 << 7)
- #define RT5640_IN_SFT1 7
- @@ -977,8 +985,7 @@
- #define RT5640_SCLK_SRC_SFT 14
- #define RT5640_SCLK_SRC_MCLK (0x0 << 14)
- #define RT5640_SCLK_SRC_PLL1 (0x1 << 14)
- -#define RT5640_SCLK_SRC_PLL1T (0x2 << 14)
- -#define RT5640_SCLK_SRC_RCCLK (0x3 << 14) /* 15MHz */
- +#define RT5640_SCLK_SRC_RCCLK (0x2 << 14) /* 15MHz */
- #define RT5640_PLL1_SRC_MASK (0x3 << 12)
- #define RT5640_PLL1_SRC_SFT 12
- #define RT5640_PLL1_SRC_MCLK (0x0 << 12)
- @@ -1205,6 +1212,14 @@
- #define RT5640_CP_FQ2_SFT 4
- #define RT5640_CP_FQ3_MASK (0x7)
- #define RT5640_CP_FQ3_SFT 0
- +#define RT5640_CP_FQ_1_5_KHZ 0
- +#define RT5640_CP_FQ_3_KHZ 1
- +#define RT5640_CP_FQ_6_KHZ 2
- +#define RT5640_CP_FQ_12_KHZ 3
- +#define RT5640_CP_FQ_24_KHZ 4
- +#define RT5640_CP_FQ_48_KHZ 5
- +#define RT5640_CP_FQ_96_KHZ 6
- +#define RT5640_CP_FQ_192_KHZ 7
- /* HPOUT charge pump (0x91) */
- #define RT5640_OSW_L_MASK (0x1 << 11)
- @@ -1699,15 +1714,15 @@
- #define RT5640_DSP_RST_PIN_LO (0x0 << 10)
- #define RT5640_DSP_RST_PIN_HI (0x1 << 10)
- #define RT5640_DSP_R_EN (0x1 << 9)
- -#define RT5640_DSP_R_EN_BIT 9
- #define RT5640_DSP_W_EN (0x1 << 8)
- -#define RT5640_DSP_W_EN_BIT 8
- #define RT5640_DSP_CMD_MASK (0xff)
- -#define RT5640_DSP_CMD_SFT 0
- -#define RT5640_DSP_CMD_MW (0x3B) /* Memory Write */
- +#define RT5640_DSP_CMD_PE (0x0d) /* Patch Entry */
- +#define RT5640_DSP_CMD_MW (0x3b) /* Memory Write */
- #define RT5640_DSP_CMD_MR (0x37) /* Memory Read */
- #define RT5640_DSP_CMD_RR (0x60) /* Register Read */
- #define RT5640_DSP_CMD_RW (0x68) /* Register Write */
- +#define RT5640_DSP_REG_DATHI (0x26) /* High Data Addr */
- +#define RT5640_DSP_REG_DATLO (0x25) /* Low Data Addr */
- /* Programmable Register Array Control 1 (0xc8) */
- #define RT5640_REG_SEQ_MASK (0xf << 12)
- @@ -2019,24 +2034,35 @@ enum {
- #define RT5640_EQ_PST_VOL_MASK (0xffff)
- #define RT5640_EQ_PST_VOL_SFT 0
- -#define RT5640_NO_JACK BIT(0)
- -#define RT5640_HEADSET_DET BIT(1)
- -#define RT5640_HEADPHO_DET BIT(2)
- +#define RT5640_M_MAMIX_L (0x1 << 13)
- +#define RT5640_M_MAMIX_R (0x1 << 12)
- +/* Vendor ID (0xfd) */
- +#define RT5640_VER_C 0x2
- +#define RT5640_VER_D 0x3
- -int rt5640_headset_detect(struct snd_soc_codec *codec, int jack_insert);
- +
- +
- +
- +/* Volume Rescale */
- +#define RT5640_VOL_RSCL_MAX 0x27
- +#define RT5640_VOL_RSCL_RANGE 0x1F
- +/* Debug String Length */
- +#define RT5640_REG_DISP_LEN 10
- /* System Clock Source */
- -#define RT5640_SCLK_S_MCLK 0
- -#define RT5640_SCLK_S_PLL1 1
- -#define RT5640_SCLK_S_PLL1_TK 2
- -#define RT5640_SCLK_S_RCCLK 3
- +enum {
- + RT5640_SCLK_S_MCLK,
- + RT5640_SCLK_S_PLL1,
- + RT5640_SCLK_S_RCCLK,
- +};
- /* PLL1 Source */
- -#define RT5640_PLL1_S_MCLK 0
- -#define RT5640_PLL1_S_BCLK1 1
- -#define RT5640_PLL1_S_BCLK2 2
- -#define RT5640_PLL1_S_BCLK3 3
- -
- +enum {
- + RT5640_PLL1_S_MCLK,
- + RT5640_PLL1_S_BCLK1,
- + RT5640_PLL1_S_BCLK2,
- + RT5640_PLL1_S_BCLK3,
- +};
- enum {
- RT5640_AIF1,
- @@ -2045,11 +2071,9 @@ enum {
- RT5640_AIFS,
- };
- -enum {
- - RT5640_U_IF1 = 0x1,
- - RT5640_U_IF2 = 0x2,
- - RT5640_U_IF3 = 0x4,
- -};
- +#define RT5640_U_IF1 (0x1)
- +#define RT5640_U_IF2 (0x1 << 1)
- +#define RT5640_U_IF3 (0x1 << 2)
- enum {
- RT5640_IF_123,
- @@ -2078,6 +2102,7 @@ struct rt5640_pll_code {
- struct rt5640_priv {
- struct snd_soc_codec *codec;
- + struct delayed_work patch_work;
- int aif_pu;
- int sysclk;
- @@ -2091,8 +2116,14 @@ struct rt5640_priv {
- int pll_out;
- int dmic_en;
- - int dsp_sw;
- + int dsp_sw; /* expected parameter setting */
- + bool dsp_play_pass;
- + bool dsp_rec_pass;
- };
- +int rt5640_conn_mux_path(struct snd_soc_codec *codec,
- + char *widget_name, char *path_name);
- +int rt5640_conn_mixer_path(struct snd_soc_codec *codec,
- + char *widget_name, char *path_name, bool enable);
- #endif /* __RT5640_H__ */
- diff --git a/sound/soc/codecs/rt56xx_ioctl.h b/sound/soc/codecs/rt56xx_ioctl.h
- new file mode 100644
- index 0000000..2b8f9f0
- --- /dev/null
- +++ b/sound/soc/codecs/rt56xx_ioctl.h
- @@ -0,0 +1,50 @@
- +#include <sound/hwdep.h>
- +#include <linux/ioctl.h>
- +
- +struct rt56xx_cmd
- +{
- + size_t number;
- + int __user *buf;
- +};
- +
- +enum
- +{
- + RT_READ_CODEC_REG_IOCTL = _IOR('R', 0x01, struct rt56xx_cmd),
- + RT_WRITE_CODEC_REG_IOCTL = _IOW('R', 0x01, struct rt56xx_cmd),
- + RT_READ_ALL_CODEC_REG_IOCTL = _IOR('R', 0x02, struct rt56xx_cmd),
- + RT_READ_CODEC_INDEX_IOCTL = _IOR('R', 0x03, struct rt56xx_cmd),
- + RT_WRITE_CODEC_INDEX_IOCTL = _IOW('R', 0x03, struct rt56xx_cmd),
- + RT_READ_CODEC_DSP_IOCTL = _IOR('R', 0x04, struct rt56xx_cmd),
- + RT_WRITE_CODEC_DSP_IOCTL = _IOW('R', 0x04, struct rt56xx_cmd),
- + RT_SET_CODEC_HWEQ_IOCTL = _IOW('R', 0x05, struct rt56xx_cmd),
- + RT_GET_CODEC_HWEQ_IOCTL = _IOR('R', 0x05, struct rt56xx_cmd),
- + RT_SET_CODEC_SPK_VOL_IOCTL = _IOW('R', 0x06, struct rt56xx_cmd),
- + RT_GET_CODEC_SPK_VOL_IOCTL = _IOR('R', 0x06, struct rt56xx_cmd),
- + RT_SET_CODEC_MIC_GAIN_IOCTL = _IOW('R', 0x07, struct rt56xx_cmd),
- + RT_GET_CODEC_MIC_GAIN_IOCTL = _IOR('R', 0x07, struct rt56xx_cmd),
- + RT_SET_CODEC_3D_SPK_IOCTL = _IOW('R', 0x08, struct rt56xx_cmd),
- + RT_GET_CODEC_3D_SPK_IOCTL = _IOR('R', 0x08, struct rt56xx_cmd),
- + RT_SET_CODEC_MP3PLUS_IOCTL = _IOW('R', 0x09, struct rt56xx_cmd),
- + RT_GET_CODEC_MP3PLUS_IOCTL = _IOR('R', 0x09, struct rt56xx_cmd),
- + RT_SET_CODEC_3D_HEADPHONE_IOCTL = _IOW('R', 0x0A, struct rt56xx_cmd),
- + RT_GET_CODEC_3D_HEADPHONE_IOCTL = _IOR('R', 0x0A, struct rt56xx_cmd),
- + RT_SET_CODEC_BASS_BACK_IOCTL = _IOW('R', 0x0B, struct rt56xx_cmd),
- + RT_GET_CODEC_BASS_BACK_IOCTL = _IOR('R', 0x0B, struct rt56xx_cmd),
- + RT_SET_CODEC_DIPOLE_SPK_IOCTL = _IOW('R', 0x0C, struct rt56xx_cmd),
- + RT_GET_CODEC_DIPOLE_SPK_IOCTL = _IOR('R', 0x0C, struct rt56xx_cmd),
- + RT_SET_CODEC_DRC_AGC_ENABLE_IOCTL = _IOW('R', 0x0D, struct rt56xx_cmd),
- + RT_GET_CODEC_DRC_AGC_ENABLE_IOCTL = _IOR('R', 0x0D, struct rt56xx_cmd),
- + RT_SET_CODEC_DSP_MODE_IOCTL = _IOW('R', 0x0E, struct rt56xx_cmd),
- + RT_GET_CODEC_DSP_MODE_IOCTL = _IOR('R', 0x0E, struct rt56xx_cmd),
- + RT_SET_CODEC_WNR_ENABLE_IOCTL = _IOW('R', 0x0F, struct rt56xx_cmd),
- + RT_GET_CODEC_WNR_ENABLE_IOCTL = _IOR('R', 0x0F, struct rt56xx_cmd),
- + RT_SET_CODEC_DRC_AGC_PAR_IOCTL = _IOW('R', 0x10, struct rt56xx_cmd),
- + RT_GET_CODEC_DRC_AGC_PAR_IOCTL = _IOR('R', 0x10, struct rt56xx_cmd),
- + RT_SET_CODEC_DIGI_BOOST_GAIN_IOCTL = _IOW('R', 0x11, struct rt56xx_cmd),
- + RT_GET_CODEC_DIGI_BOOST_GAIN_IOCTL = _IOR('R', 0x11, struct rt56xx_cmd),
- + RT_SET_CODEC_NOISE_GATE_IOCTL = _IOW('R', 0x12, struct rt56xx_cmd),
- + RT_GET_CODEC_NOISE_GATE_IOCTL = _IOR('R', 0x12, struct rt56xx_cmd),
- + RT_SET_CODEC_DRC_AGC_COMP_IOCTL = _IOW('R', 0x13, struct rt56xx_cmd),
- + RT_GET_CODEC_DRC_AGC_COMP_IOCTL = _IOR('R', 0x13, struct rt56xx_cmd),
- + RT_GET_CODEC_ID = _IOR('R', 0x30, struct rt56xx_cmd),
- +};
- diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
- index 2a8b4f1..1217aaa 100644
- --- a/sound/soc/tegra/Kconfig
- +++ b/sound/soc/tegra/Kconfig
- @@ -200,6 +200,8 @@ config SND_SOC_TEGRA_RT5640
- select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
- select SND_SOC_TEGRA30_SPDIF if ARCH_TEGRA_3x_SOC
- select SND_SOC_RT5640
- + select SND_SOC_RT5642
- + select SND_HWDEP
- select SND_SOC_SPDIF
- select SND_SOC_TEGRA30_DAM if ARCH_TEGRA_3x_SOC
- help
- @@ -228,3 +230,6 @@ config SND_SOC_TEGRA_MAX98095
- Say Y or M here if you want to add support for SoC audio on Tegra
- boards using the MAX98095 codec. Currently, only supported board is
- Cardhu.
- +config HEADSET_FUNCTION
- + tristate "Headset detection function"
- + default n
- diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
- index d546046..adf7588 100644
- --- a/sound/soc/tegra/Makefile
- +++ b/sound/soc/tegra/Makefile
- @@ -38,4 +38,5 @@ obj-$(CONFIG_SND_SOC_TEGRA_MAX98088) += snd-soc-tegra-max98088.o
- obj-$(CONFIG_SND_SOC_TEGRA_TLV320AIC326X) += snd-soc-tegra-aic326x.o
- obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o
- obj-$(CONFIG_SND_SOC_TEGRA_MAX98095) += snd-soc-tegra-max98095.o
- +obj-$(CONFIG_HEADSET_FUNCTION) += headset.o
- obj-$(CONFIG_SND_SOC_TEGRA_P1852) += snd-soc-tegra-p1852.o
- diff --git a/sound/soc/tegra/headset.c b/sound/soc/tegra/headset.c
- new file mode 100644
- index 0000000..368d0cd
- --- /dev/null
- +++ b/sound/soc/tegra/headset.c
- @@ -0,0 +1,627 @@
- +/*
- + * Headset device detection driver.
- + *
- + * Copyright (C) 2011 ASUSTek Corporation.
- + *
- + * Authors:
- + * Jason Cheng <jason4_cheng@asus.com>
- + *
- + * This software is licensed under the terms of the GNU General Public
- + * License version 2, as published by the Free Software Foundation, and
- + * may be copied, distributed, and modified under those terms.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + */
- +#include <linux/module.h>
- +#include <linux/fs.h>
- +#include <linux/interrupt.h>
- +#include <linux/workqueue.h>
- +#include <linux/irq.h>
- +#include <linux/delay.h>
- +#include <linux/types.h>
- +#include <linux/input.h>
- +#include <linux/mutex.h>
- +#include <linux/errno.h>
- +#include <linux/err.h>
- +#include <linux/hrtimer.h>
- +#include <linux/timer.h>
- +#include <linux/switch.h>
- +#include <linux/input.h>
- +#include <linux/slab.h>
- +#include <asm/gpio.h>
- +#include <asm/uaccess.h>
- +#include <asm/string.h>
- +#include <sound/soc.h>
- +#include "../gpio-names.h"
- +#include "../codecs/rt5640.h"
- +#include <mach/board-grouper-misc.h>
- +#include <mach/pinmux.h>
- +#include "../board.h"
- +#include "../board-grouper.h"
- +MODULE_DESCRIPTION("Headset detection driver");
- +MODULE_LICENSE("GPL");
- +
- +#define DEFAULT_PINMUX(_pingroup, _mux, _pupd, _tri, _io) \
- + { \
- + .pingroup = TEGRA_PINGROUP_##_pingroup, \
- + .func = TEGRA_MUX_##_mux, \
- + .pupd = TEGRA_PUPD_##_pupd, \
- + .tristate = TEGRA_TRI_##_tri, \
- + .io = TEGRA_PIN_##_io, \
- + .lock = TEGRA_PIN_LOCK_DEFAULT, \
- + .od = TEGRA_PIN_OD_DEFAULT, \
- + .ioreset = TEGRA_PIN_IO_RESET_DEFAULT, \
- + }
- +
- +/*----------------------------------------------------------------------------
- +** FUNCTION DECLARATION
- +**----------------------------------------------------------------------------*/
- +static int __init headset_init(void);
- +static void __exit headset_exit(void);
- +static irqreturn_t detect_irq_handler(int irq, void *dev_id);
- +static void detection_work(struct work_struct *work);
- +static int jack_config_gpio(void);
- +static irqreturn_t lineout_irq_handler(int irq, void *dev_id);
- +static void lineout_work_queue(struct work_struct *work);
- +static void dock_work_queue(struct work_struct *work);
- +static int lineout_config_gpio(u32 project_info);
- +static void detection_work(struct work_struct *work);
- +static int btn_config_gpio(void);
- +static int switch_config_gpio(void);
- +int hs_micbias_power(int on);
- +static irqreturn_t dockin_irq_handler(int irq, void *dev_id);
- +static void set_dock_switches(void);
- +/*----------------------------------------------------------------------------
- +** GLOBAL VARIABLES
- +**----------------------------------------------------------------------------*/
- +#define JACK_GPIO (TEGRA_GPIO_PW2)
- +#define LINEOUT_GPIO_NAKASI (TEGRA_GPIO_PW3)
- +#define LINEOUT_GPIO_BACH (TEGRA_GPIO_PX6)
- +#define HOOK_GPIO (TEGRA_GPIO_PX2)
- +#define UART_HEADPHONE_SWITCH (TEGRA_GPIO_PS2)
- +#define ON (1)
- +#define OFF (0)
- +
- +enum{
- + NO_DEVICE = 0,
- + HEADSET_WITH_MIC = 1,
- + HEADSET_WITHOUT_MIC = 2,
- +};
- +
- +struct headset_data {
- + struct switch_dev sdev;
- + struct input_dev *input;
- + unsigned int irq;
- + struct hrtimer timer;
- + ktime_t debouncing_time;
- +};
- +
- +static struct headset_data *hs_data;
- +bool headset_alive = false;
- +EXPORT_SYMBOL(headset_alive);
- +bool lineout_alive;
- +EXPORT_SYMBOL(lineout_alive);
- +
- +static struct workqueue_struct *g_detection_work_queue;
- +static DECLARE_WORK(g_detection_work, detection_work);
- +
- +extern struct snd_soc_codec *rt5640_audio_codec;
- +struct work_struct headset_work;
- +struct work_struct lineout_work;
- +struct work_struct dock_work;
- +static bool UART_enable = false;
- +static unsigned int revision;
- +static u32 lineout_gpio;
- +static int gpio_dock_in = 0;
- +
- +static struct switch_dev dock_switch = {
- + .name = "dock",
- +};
- +
- +static struct switch_dev audio_switch = {
- + .name = "usb_audio",
- +};
- +
- +static ssize_t headset_name_show(struct switch_dev *sdev, char *buf)
- +{
- + switch (switch_get_state(&hs_data->sdev)){
- + case NO_DEVICE:{
- + return sprintf(buf, "%s\n", "No Device");
- + }
- + case HEADSET_WITH_MIC:{
- + return sprintf(buf, "%s\n", "HEADSET");
- + }
- + case HEADSET_WITHOUT_MIC:{
- + return sprintf(buf, "%s\n", "HEADPHONE");
- + }
- + }
- + return -EINVAL;
- +}
- +
- +static ssize_t headset_state_show(struct switch_dev *sdev, char *buf)
- +{
- + switch (switch_get_state(&hs_data->sdev)){
- + case NO_DEVICE:
- + return sprintf(buf, "%d\n", 0);
- + case HEADSET_WITH_MIC:
- + return sprintf(buf, "%d\n", 1);
- + case HEADSET_WITHOUT_MIC:
- + return sprintf(buf, "%d\n", 2);
- + }
- + return -EINVAL;
- +}
- +
- +static void tristate_uart(void)
- +{
- + enum tegra_pingroup pingroup = TEGRA_PINGROUP_ULPI_DATA0;
- + enum tegra_pullupdown pupd = TEGRA_PUPD_PULL_DOWN;
- + enum tegra_pin_io io = TEGRA_PIN_INPUT;
- + enum tegra_tristate tristate = TEGRA_TRI_TRISTATE;
- +
- + tegra_pinmux_set_pullupdown(pingroup, pupd);
- + tegra_pinmux_set_tristate(pingroup, tristate);
- +}
- +
- +
- +static void pulldown_uart(void)
- +{
- + enum tegra_pingroup pingroupTx = TEGRA_PINGROUP_ULPI_DATA0;
- + enum tegra_pingroup pingroupRx = TEGRA_PINGROUP_ULPI_DATA1;
- + enum tegra_pullupdown pupd = TEGRA_PUPD_PULL_DOWN;
- + enum tegra_pin_io io = TEGRA_PIN_INPUT;
- +
- + tegra_pinmux_set_pullupdown(pingroupTx, pupd);
- + tegra_pinmux_set_io(pingroupTx, io);
- +// tegra_pinmux_set_pullupdown(pingroupRx, pupd);
- + // tegra_pinmux_set_io(pingroupRx, io);
- +}
- +
- +
- +static void normal_uart(void)
- +{
- + struct tegra_pingroup_config debug_uart [] = {
- + DEFAULT_PINMUX(ULPI_DATA0, UARTA, NORMAL, NORMAL, OUTPUT),
- + };
- + tegra_pinmux_config_table(debug_uart, ARRAY_SIZE(debug_uart));
- +
- + // tegra_pinmux_set_pullupdown(pingroupRx, pupd);
- + // tegra_pinmux_set_io(pingroupRx, ioIn);
- +
- +}
- +
- +
- +static void enable_uart(void)
- +{
- + struct tegra_pingroup_config debug_uart [] = {
- + DEFAULT_PINMUX(ULPI_DATA0, ULPI, NORMAL, NORMAL, OUTPUT),
- + };
- + tegra_pinmux_config_table(debug_uart, ARRAY_SIZE(debug_uart));
- +}
- +
- +
- +static void disable_uart(void)
- +{
- + struct tegra_pingroup_config debug_uart [] = {
- + DEFAULT_PINMUX(ULPI_DATA0, ULPI, PULL_UP, TRISTATE, OUTPUT),
- + };
- + tegra_pinmux_config_table(debug_uart, ARRAY_SIZE(debug_uart));
- +}
- +static void insert_headset(void)
- +{
- + struct snd_soc_dapm_context *dapm;
- +
- + dapm = &rt5640_audio_codec->dapm;
- +
- + if(gpio_get_value(lineout_gpio) == 0 && UART_enable){
- + printk("%s: debug board\n", __func__);
- + switch_set_state(&hs_data->sdev, NO_DEVICE);
- + hs_micbias_power(OFF);
- + headset_alive = false;
- + gpio_direction_output(UART_HEADPHONE_SWITCH, 0);
- + normal_uart();
- + }else if(gpio_get_value(HOOK_GPIO)){
- + printk("%s: headphone\n", __func__);
- + switch_set_state(&hs_data->sdev, HEADSET_WITHOUT_MIC);
- + hs_micbias_power(OFF);
- + pulldown_uart();
- + gpio_direction_output(UART_HEADPHONE_SWITCH, 1);
- + headset_alive = false;
- + }else{
- + printk("%s: headset\n", __func__);
- + switch_set_state(&hs_data->sdev, HEADSET_WITHOUT_MIC);
- + hs_micbias_power(ON);
- + pulldown_uart();
- + gpio_direction_output(UART_HEADPHONE_SWITCH, 1);
- + headset_alive = true;
- + }
- + hs_data->debouncing_time = ktime_set(0, 100000000); /* 100 ms */
- +}
- +static void remove_headset(void)
- +{
- + switch_set_state(&hs_data->sdev, NO_DEVICE);
- + hs_data->debouncing_time = ktime_set(0, 100000000); /* 100 ms */
- + headset_alive = false;
- + tristate_uart();
- + gpio_direction_output(UART_HEADPHONE_SWITCH, 0);
- +}
- +
- +static void detection_work(struct work_struct *work)
- +{
- + unsigned long irq_flags;
- + int cable_in1;
- + int mic_in = 0;
- + hs_micbias_power(ON);
- + /* Disable headset interrupt while detecting.*/
- + local_irq_save(irq_flags);
- + disable_irq(hs_data->irq);
- + local_irq_restore(irq_flags);
- +
- + /* Delay 1000ms for pin stable. */
- + msleep(1000);
- +
- + /* Restore IRQs */
- + local_irq_save(irq_flags);
- + enable_irq(hs_data->irq);
- + local_irq_restore(irq_flags);
- +
- + if (gpio_get_value(JACK_GPIO) != 0) {
- + /* Headset not plugged in */
- +
- +// if (switch_get_state(&hs_data->sdev) == HEADSET_WITH_MIC ||
- +// switch_get_state(&hs_data->sdev) == HEADSET_WITHOUT_MIC)
- + remove_headset();
- + goto closed_micbias;
- + }
- +
- + cable_in1 = gpio_get_value(JACK_GPIO);
- + mic_in = gpio_get_value(HOOK_GPIO);
- + if (cable_in1 == 0) {
- + printk("HOOK_GPIO value: %d\n", mic_in);
- + if(switch_get_state(&hs_data->sdev) == NO_DEVICE)
- + insert_headset();
- + else if ( mic_in == 1)
- + goto closed_micbias;
- + } else{
- + printk("HEADSET: Jack-in GPIO is low, but not a headset \n");
- + goto closed_micbias;
- + }
- + return;
- +
- +closed_micbias:
- + hs_micbias_power(OFF);
- + return;
- +}
- +
- +static enum hrtimer_restart detect_event_timer_func(struct hrtimer *data)
- +{
- + queue_work(g_detection_work_queue, &g_detection_work);
- + return HRTIMER_NORESTART;
- +}
- +
- +/**********************************************************
- +** Function: Jack detection-in gpio configuration function
- +** Parameter: none
- +** Return value: if sucess, then returns 0
- +**
- +************************************************************/
- +static int jack_config_gpio()
- +{
- + int ret;
- +
- + printk("HEADSET: Config Jack-in detection gpio\n");
- + hs_micbias_power(ON);
- + tegra_gpio_enable(JACK_GPIO);
- + ret = gpio_request(JACK_GPIO, "h2w_detect");
- + ret = gpio_direction_input(JACK_GPIO);
- +
- + hs_data->irq = gpio_to_irq(JACK_GPIO);
- + ret = request_irq(hs_data->irq, detect_irq_handler,
- + IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "h2w_detect", NULL);
- +
- + ret = irq_set_irq_wake(hs_data->irq, 1);
- + msleep(1);
- + if (gpio_get_value(JACK_GPIO) == 0){
- + insert_headset();
- + }else {
- + hs_micbias_power(OFF);
- + headset_alive = false;
- + switch_set_state(&hs_data->sdev, NO_DEVICE);
- + remove_headset();
- + }
- +
- + return 0;
- +}
- +
- +/**********************************************************
- +** Function: Headset Hook Key Detection interrupt handler
- +** Parameter: irq
- +** Return value: IRQ_HANDLED
- +** High: Hook button pressed
- +************************************************************/
- +static int btn_config_gpio()
- +{
- + int ret;
- +
- + printk("HEADSET: Config Headset Button detection gpio\n");
- +
- + tegra_gpio_enable(HOOK_GPIO);
- + ret = gpio_request(HOOK_GPIO, "btn_INT");
- + ret = gpio_direction_input(HOOK_GPIO);
- +
- + return 0;
- +}
- +
- +static void lineout_work_queue(struct work_struct *work)
- +{
- + msleep(300);
- +
- + if (gpio_get_value(lineout_gpio) == 0){
- + printk("LINEOUT: LineOut inserted\n");
- + lineout_alive = true;
- + }else if(gpio_get_value(lineout_gpio)){
- + printk("LINEOUT: LineOut removed\n");
- + lineout_alive = false;
- + }
- +
- +}
- +
- +static void set_dock_switches(void)
- +{
- + bool docked = !gpio_get_value(gpio_dock_in);
- +
- + /* LE desk dock == 3, undocked == 0. */
- + switch_set_state(&dock_switch, docked ? 3 : 0);
- +
- + /*
- + * Analog audio == 1, no audio == 0.
- + * Note that because we cannot detect the presence of a 3.5mm jack
- + * in the dock's audio socket, when docked, audio is always on.
- + */
- + switch_set_state(&audio_switch, docked ? 1 : 0);
- +}
- +
- +static void dock_work_queue(struct work_struct *work)
- +{
- + set_dock_switches();
- +}
- +
- +/**********************************************************
- +** Function: LineOut Detection configuration function
- +** Parameter: none
- +** Return value: IRQ_HANDLED
- +**
- +************************************************************/
- +static int lineout_config_gpio(u32 project_info)
- +{
- + int ret;
- +
- + printk("HEADSET: Config LineOut detection gpio\n");
- + if(project_info == GROUPER_PROJECT_BACH)
- + lineout_gpio = LINEOUT_GPIO_BACH;
- + else if(project_info == GROUPER_PROJECT_NAKASI)
- + lineout_gpio = LINEOUT_GPIO_NAKASI;
- + tegra_gpio_enable(lineout_gpio);
- + ret = gpio_request(lineout_gpio, "lineout_int");
- + ret = gpio_direction_input(lineout_gpio);
- +#if 0
- + ret = request_irq(gpio_to_irq(LINEOUT_GPIO), &lineout_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "lineout_int", 0);
- +#endif
- + if (gpio_get_value(lineout_gpio) == 0)
- + lineout_alive = true;
- + else
- + lineout_alive = false;
- +
- + return 0;
- +}
- +
- +static int switch_config_gpio()
- +{
- + int ret;
- +
- + printk("HEADSET: Config uart<->headphone gpio\n");
- +
- + tegra_gpio_enable(UART_HEADPHONE_SWITCH);
- + ret = gpio_request(UART_HEADPHONE_SWITCH, "uart_headphone_switch");
- +
- + return 0;
- +}
- +
- +static int dockin_config_gpio()
- +{
- + int ret = 0;
- + int irq_num = 0;
- +
- + irq_num = gpio_to_irq(gpio_dock_in);
- + ret = request_irq(irq_num, dockin_irq_handler,
- + IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING | IRQF_SHARED, "dock_detect", hs_data);
- + if(ret < 0)
- + printk("%s: request irq fail errno = %d\n", __func__, ret);
- +
- + return ret;
- +}
- +
- +static irqreturn_t dockin_irq_handler(int irq, void *dev_id)
- +{
- + schedule_work(&dock_work);
- +
- + return IRQ_HANDLED;
- +}
- +
- +/**********************************************************
- +** Function: LineOut detection interrupt handler
- +** Parameter: dedicated irq
- +** Return value: if sucess, then returns IRQ_HANDLED
- +**
- +************************************************************/
- +static irqreturn_t lineout_irq_handler(int irq, void *dev_id)
- +{
- + schedule_work(&lineout_work);
- + return IRQ_HANDLED;
- +}
- +
- +/**********************************************************
- +** Function: Headset jack-in detection interrupt handler
- +** Parameter: dedicated irq
- +** Return value: if sucess, then returns IRQ_HANDLED
- +**
- +************************************************************/
- +static irqreturn_t detect_irq_handler(int irq, void *dev_id)
- +{
- + int value1, value2;
- + int retry_limit = 10;
- +
- + do {
- + value1 = gpio_get_value(JACK_GPIO);
- + irq_set_irq_type(hs_data->irq, value1 ?
- + IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING);
- + value2 = gpio_get_value(JACK_GPIO);
- + }while (value1 != value2 && retry_limit-- > 0);
- +
- + if ((switch_get_state(&hs_data->sdev) == NO_DEVICE) ^ value2){
- + hrtimer_start(&hs_data->timer, hs_data->debouncing_time, HRTIMER_MODE_REL);
- + }
- +
- + return IRQ_HANDLED;
- +}
- +
- +static int codec_micbias_power(int on)
- +{
- + if(on){
- + //for ALC5642
- + if(rt5640_audio_codec == NULL){
- + printk("%s: No rt5640_audio_codec - set micbias on fail\n", __func__);
- + return 0;
- + }
- +#if 0
- + snd_soc_update_bits(rt5640_audio_codec, RT5640_PWR_ANLG1, RT5640_PWR_LDO2, RT5640_PWR_LDO2); /* Enable LDO2 */
- + snd_soc_update_bits(rt5640_audio_codec, RT5640_PWR_ANLG2, RT5640_PWR_MB1, RT5640_PWR_MB1); /*Enable MicBias1 */
- + //for ALC5642
- +#endif
- + }else{
- + //for ALC5642
- + if(rt5640_audio_codec == NULL){
- + printk("%s: No rt5640_audio_codec - set micbias off fail\n", __func__);
- + return 0;
- + }
- + snd_soc_update_bits(rt5640_audio_codec, RT5640_PWR_ANLG2, RT5640_PWR_MB1, 0); /* Disable MicBias1 */
- + snd_soc_update_bits(rt5640_audio_codec, RT5640_PWR_ANLG1, RT5640_PWR_LDO2, 0); /* Disable LDO2 */
- + //for ALC5642
- + }
- + return 0;
- +}
- +
- +
- +int hs_micbias_power(int on)
- +{
- + static int nLastVregStatus = -1;
- +
- + if(on && nLastVregStatus!=ON){
- + printk("HEADSET: Turn on micbias power\n");
- + nLastVregStatus = ON;
- + codec_micbias_power(ON);
- + }
- + else if(!on && nLastVregStatus!=OFF){
- + printk("HEADSET: Turn off micbias power\n");
- + nLastVregStatus = OFF;
- + codec_micbias_power(OFF);
- + }
- + return 0;
- +}
- +EXPORT_SYMBOL(hs_micbias_power);
- +
- +/**********************************************************
- +** Function: Headset driver init function
- +** Parameter: none
- +** Return value: none
- +**
- +************************************************************/
- +static int __init headset_init(void)
- +{
- + u32 project_info = grouper_get_project_id();
- + u32 pmic_id = grouper_query_pmic_id();
- +
- + printk(KERN_INFO "%s+ #####\n", __func__);
- + int ret;
- +
- + printk("HEADSET: Headset detection init\n");
- +
- + if (project_info == GROUPER_PROJECT_BACH)
- + gpio_dock_in = TEGRA_GPIO_PO5;
- + else
- + gpio_dock_in = TEGRA_GPIO_PU4;
- +
- + if(project_info == GROUPER_PROJECT_BACH ||
- + (project_info == GROUPER_PROJECT_NAKASI && pmic_id ==GROUPER_PMIC_TI))
- + UART_enable = true;
- +
- + revision = grouper_query_pcba_revision();
- +
- + hs_data = kzalloc(sizeof(struct headset_data), GFP_KERNEL);
- + if (!hs_data)
- + return -ENOMEM;
- +
- + hs_data->debouncing_time = ktime_set(0, 100000000); /* 100 ms */
- + hs_data->sdev.name = "h2w";
- + hs_data->sdev.print_name = headset_name_show;
- + hs_data->sdev.print_state = headset_state_show;
- +
- + ret = switch_dev_register(&hs_data->sdev);
- + if (ret < 0)
- + goto err_switch_dev_register;
- +
- + WARN_ON(switch_dev_register(&dock_switch));
- + WARN_ON(switch_dev_register(&audio_switch));
- + /* Make sure dock switches are correct at boot */
- + set_dock_switches();
- +
- + g_detection_work_queue = create_workqueue("detection");
- +
- + hrtimer_init(&hs_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- + hs_data->timer.function = detect_event_timer_func;
- +
- + printk("HEADSET: Headset detection mode\n");
- + lineout_config_gpio(project_info);
- + btn_config_gpio();/*Config hook detection GPIO*/
- + switch_config_gpio(); /*Config uart and headphone switch*/
- + jack_config_gpio();/*Config jack detection GPIO*/
- + INIT_WORK(&lineout_work, lineout_work_queue);
- + INIT_WORK(&dock_work, dock_work_queue);
- + dockin_config_gpio();
- +
- + printk(KERN_INFO "%s- #####\n", __func__);
- + return 0;
- +
- +err_switch_dev_register:
- + printk(KERN_ERR "Headset: Failed to register driver\n");
- +
- + return ret;
- +}
- +
- +/**********************************************************
- +** Function: Headset driver exit function
- +** Parameter: none
- +** Return value: none
- +**
- +************************************************************/
- +static void __exit headset_exit(void)
- +{
- + printk("HEADSET: Headset exit\n");
- + if (switch_get_state(&hs_data->sdev))
- + remove_headset();
- + gpio_free(JACK_GPIO);
- + gpio_free(HOOK_GPIO);
- + gpio_free(lineout_gpio);
- +
- + free_irq(hs_data->irq, 0);
- + destroy_workqueue(g_detection_work_queue);
- + switch_dev_unregister(&hs_data->sdev);
- + switch_dev_unregister(&dock_switch);
- + switch_dev_unregister(&audio_switch);
- +}
- +
- +module_init(headset_init);
- +module_exit(headset_exit);
- diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
- index f277d28..7186f3d 100644
- --- a/sound/soc/tegra/tegra_pcm.c
- +++ b/sound/soc/tegra/tegra_pcm.c
- @@ -2,7 +2,7 @@
- * tegra_pcm.c - Tegra PCM driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- - * Copyright (C) 2010 - NVIDIA, Inc.
- + * Copyright (C) 2010-2012 - NVIDIA, Inc.
- *
- * Based on code copyright/by:
- *
- @@ -29,6 +29,7 @@
- *
- */
- +#include <asm/mach-types.h>
- #include <linux/module.h>
- #include <linux/dma-mapping.h>
- #include <linux/slab.h>
- @@ -41,6 +42,9 @@
- #define DRV_NAME "tegra-pcm-audio"
- +#define PERIOD_BYTES_MAX (PAGE_SIZE * 2)
- +#define PERIODS_MAX 64
- +
- static const struct snd_pcm_hardware tegra_pcm_hardware = {
- .info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- @@ -51,10 +55,10 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = {
- .channels_min = 1,
- .channels_max = 2,
- .period_bytes_min = 128,
- - .period_bytes_max = PAGE_SIZE,
- + .period_bytes_max = PERIOD_BYTES_MAX,
- .periods_min = 2,
- - .periods_max = 8,
- - .buffer_bytes_max = PAGE_SIZE * 8,
- + .periods_max = PERIODS_MAX,
- + .buffer_bytes_max = PERIOD_BYTES_MAX * PERIODS_MAX,
- .fifo_size = 4,
- };
- @@ -262,8 +266,11 @@ static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
- spin_lock_irqsave(&prtd->lock, flags);
- prtd->running = 0;
- spin_unlock_irqrestore(&prtd->lock, flags);
- - tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[0]);
- - tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[1]);
- + tegra_dma_cancel(prtd->dma_chan);
- + if (prtd->dma_req[0].status == -TEGRA_DMA_REQ_ERROR_ABORTED)
- + prtd->dma_req[0].complete(&prtd->dma_req[0]);
- + if (prtd->dma_req[1].status == -TEGRA_DMA_REQ_ERROR_ABORTED)
- + prtd->dma_req[1].complete(&prtd->dma_req[1]);
- break;
- default:
- return -EINVAL;
- @@ -386,10 +393,19 @@ static void tegra_pcm_free(struct snd_pcm *pcm)
- tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
- }
- +static int tegra_pcm_probe(struct snd_soc_platform *platform)
- +{
- + if(machine_is_kai() || machine_is_grouper())
- + platform->dapm.idle_bias_off = 1;
- +
- + return 0;
- +}
- +
- struct snd_soc_platform_driver tegra_pcm_platform = {
- .ops = &tegra_pcm_ops,
- .pcm_new = tegra_pcm_new,
- .pcm_free = tegra_pcm_free,
- + .probe = tegra_pcm_probe,
- };
- static int __devinit tegra_pcm_platform_probe(struct platform_device *pdev)
- diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c
- index 268228e..1fff7ec 100644
- --- a/sound/soc/tegra/tegra_rt5640.c
- +++ b/sound/soc/tegra/tegra_rt5640.c
- @@ -69,6 +69,8 @@ struct tegra_rt5640 {
- #ifdef CONFIG_SWITCH
- int jack_status;
- #endif
- + enum snd_soc_bias_level bias_level;
- + volatile int clock_enabled;
- };
- static int tegra_rt5640_hw_params(struct snd_pcm_substream *substream,
- @@ -277,11 +279,14 @@ static int tegra_rt5640_jack_notifier(struct notifier_block *self,
- struct snd_soc_codec *codec = jack->codec;
- struct snd_soc_card *card = codec->card;
- struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
- + struct tegra_rt5640_platform_data *pdata = machine->pdata;
- enum headset_state state = BIT_NO_HEADSET;
- unsigned char status_jack;
- -
- +#if 0
- if (jack == &tegra_rt5640_hp_jack) {
- if (action) {
- + /* Enable ext mic; enable signal is active-low */
- + gpio_direction_output(pdata->gpio_ext_mic_en, 0);
- if (!strncmp(machine->pdata->codec_name, "rt5639", 6))
- status_jack = rt5639_headset_detect(codec, 1);
- else if (!strncmp(machine->pdata->codec_name, "rt5640",
- @@ -302,6 +307,8 @@ static int tegra_rt5640_jack_notifier(struct notifier_block *self,
- SND_JACK_MICROPHONE;
- }
- } else {
- + /* Disable ext mic; enable signal is active-low */
- + gpio_direction_output(pdata->gpio_ext_mic_en, 1);
- if (!strncmp(machine->pdata->codec_name, "rt5639", 6))
- rt5639_headset_detect(codec, 0);
- else if (!strncmp(machine->pdata->codec_name, "rt5640",
- @@ -312,7 +319,7 @@ static int tegra_rt5640_jack_notifier(struct notifier_block *self,
- machine->jack_status &= ~SND_JACK_MICROPHONE;
- }
- }
- -
- +#endif
- switch (machine->jack_status) {
- case SND_JACK_HEADPHONE:
- state = BIT_HEADSET_NO_MIC;
- @@ -427,10 +434,11 @@ static int tegra_rt5640_event_ext_mic(struct snd_soc_dapm_widget *w,
- }
- static const struct snd_soc_dapm_widget cardhu_dapm_widgets[] = {
- - SND_SOC_DAPM_SPK("Int Spk", tegra_rt5640_event_int_spk),
- - SND_SOC_DAPM_HP("Headphone Jack", tegra_rt5640_event_hp),
- - SND_SOC_DAPM_MIC("Mic Jack", tegra_rt5640_event_ext_mic),
- - SND_SOC_DAPM_MIC("Int Mic", tegra_rt5640_event_int_mic),
- + SND_SOC_DAPM_SPK("Int Spk", NULL),
- + SND_SOC_DAPM_HP("Headphone Jack", NULL),
- + SND_SOC_DAPM_MIC("Mic Jack", NULL),
- + SND_SOC_DAPM_MIC("Int Mic", NULL),
- + SND_SOC_DAPM_SPK("AUX", NULL),
- };
- static const struct snd_soc_dapm_route cardhu_audio_map[] = {
- @@ -440,11 +448,12 @@ static const struct snd_soc_dapm_route cardhu_audio_map[] = {
- {"Int Spk", NULL, "SPORN"},
- {"Int Spk", NULL, "SPOLP"},
- {"Int Spk", NULL, "SPOLN"},
- - {"micbias1", NULL, "Mic Jack"},
- - {"IN1P", NULL, "micbias1"},
- - {"IN1N", NULL, "micbias1"},
- - {"micbias1", NULL, "Int Mic"},
- - {"IN2P", NULL, "micbias1"},
- + {"DMIC L1", NULL, "Int Mic"},
- + {"DMIC R1", NULL, "Int Mic"},
- + {"micbias2", NULL, "Mic Jack"},
- + {"MIC2", NULL, "micbias2"},
- + {"AUX", NULL, "LOUTL"},
- + {"AUX", NULL, "LOUTR"},
- };
- static const struct snd_kcontrol_new cardhu_controls[] = {
- @@ -452,6 +461,7 @@ static const struct snd_kcontrol_new cardhu_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Mic Jack"),
- SOC_DAPM_PIN_SWITCH("Int Mic"),
- + SOC_DAPM_PIN_SWITCH("AUX"),
- };
- static int tegra_rt5640_init(struct snd_soc_pcm_runtime *rtd)
- @@ -463,69 +473,18 @@ static int tegra_rt5640_init(struct snd_soc_pcm_runtime *rtd)
- struct tegra_rt5640_platform_data *pdata = machine->pdata;
- int ret;
- - if (gpio_is_valid(pdata->gpio_spkr_en)) {
- - ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
- - if (ret) {
- - dev_err(card->dev, "cannot get spkr_en gpio\n");
- - return ret;
- - }
- - machine->gpio_requested |= GPIO_SPKR_EN;
- - gpio_direction_output(pdata->gpio_spkr_en, 0);
- - }
- - if (gpio_is_valid(pdata->gpio_hp_mute)) {
- - ret = gpio_request(pdata->gpio_hp_mute, "hp_mute");
- - if (ret) {
- - dev_err(card->dev, "cannot get hp_mute gpio\n");
- - return ret;
- - }
- - machine->gpio_requested |= GPIO_HP_MUTE;
- - gpio_direction_output(pdata->gpio_hp_mute, 0);
- - }
- - if (gpio_is_valid(pdata->gpio_int_mic_en)) {
- - ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en");
- - if (ret) {
- - dev_err(card->dev, "cannot get int_mic_en gpio\n");
- - return ret;
- - }
- - machine->gpio_requested |= GPIO_INT_MIC_EN;
- /* Disable int mic; enable signal is active-high */
- - gpio_direction_output(pdata->gpio_int_mic_en, 0);
- - }
- - if (gpio_is_valid(pdata->gpio_ext_mic_en)) {
- - ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en");
- - if (ret) {
- - dev_err(card->dev, "cannot get ext_mic_en gpio\n");
- - return ret;
- - }
- - machine->gpio_requested |= GPIO_EXT_MIC_EN;
- - /* Enable ext mic; enable signal is active-low */
- - gpio_direction_output(pdata->gpio_ext_mic_en, 0);
- - }
- - if (gpio_is_valid(pdata->gpio_hp_det)) {
- - tegra_rt5640_hp_jack_gpio.gpio = pdata->gpio_hp_det;
- - snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
- - &tegra_rt5640_hp_jack);
- -#ifndef CONFIG_SWITCH
- - snd_soc_jack_add_pins(&tegra_rt5640_hp_jack,
- - ARRAY_SIZE(tegra_rt5640_hp_jack_pins),
- - tegra_rt5640_hp_jack_pins);
- -#else
- - snd_soc_jack_notifier_register(&tegra_rt5640_hp_jack,
- - &tegra_rt5640_jack_detect_nb);
- -#endif
- - snd_soc_jack_add_gpios(&tegra_rt5640_hp_jack,
- - 1,
- - &tegra_rt5640_hp_jack_gpio);
- - machine->gpio_requested |= GPIO_HP_DET;
- - }
- +
- + machine->bias_level = SND_SOC_BIAS_STANDBY;
- + machine->clock_enabled = 1;
- ret = snd_soc_add_controls(codec, cardhu_controls,
- ARRAY_SIZE(cardhu_controls));
- @@ -540,7 +499,11 @@ static int tegra_rt5640_init(struct snd_soc_pcm_runtime *rtd)
- /* FIXME: Calculate automatically based on DAPM routes? */
- snd_soc_dapm_nc_pin(dapm, "LOUTL");
- snd_soc_dapm_nc_pin(dapm, "LOUTR");
- -
- + snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
- + snd_soc_dapm_disable_pin(dapm, "Int Spk");
- + snd_soc_dapm_disable_pin(dapm, "Mic Jack");
- + snd_soc_dapm_disable_pin(dapm, "Int Mic");
- + snd_soc_dapm_disable_pin(dapm, "AUX");
- snd_soc_dapm_sync(dapm);
- return 0;
- @@ -571,16 +534,49 @@ static struct snd_soc_dai_link tegra_rt5640_dai[] = {
- .stream_name = "BT SCO PCM",
- .codec_name = "spdif-dit.1",
- .platform_name = "tegra-pcm-audio",
- - .cpu_dai_name = "tegra30-i2s.4",
- + .cpu_dai_name = "tegra30-i2s.3",
- .codec_dai_name = "dit-hifi",
- .ops = &tegra_rt5640_bt_sco_ops,
- },
- };
- +static int tegra_rt5640_set_bias_level(struct snd_soc_card *card,
- + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
- +{
- + struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
- +
- + if (machine->bias_level == SND_SOC_BIAS_OFF &&
- + level != SND_SOC_BIAS_OFF && (!machine->clock_enabled)) {
- + machine->clock_enabled = 1;
- + tegra_asoc_utils_clk_enable(&machine->util_data);
- + machine->bias_level = level;
- + }
- +
- + return 0;
- +}
- +
- +static int tegra_rt5640_set_bias_level_post(struct snd_soc_card *card,
- + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
- +{
- + struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
- +
- + if (machine->bias_level != SND_SOC_BIAS_OFF &&
- + level == SND_SOC_BIAS_OFF && machine->clock_enabled) {
- + machine->clock_enabled = 0;
- + tegra_asoc_utils_clk_disable(&machine->util_data);
- + }
- +
- + machine->bias_level = level;
- +
- + return 0 ;
- +}
- +
- static struct snd_soc_card snd_soc_tegra_rt5640 = {
- .name = "tegra-rt5640",
- .dai_link = tegra_rt5640_dai,
- .num_links = ARRAY_SIZE(tegra_rt5640_dai),
- + .set_bias_level = tegra_rt5640_set_bias_level,
- + .set_bias_level_post = tegra_rt5640_set_bias_level_post,
- };
- static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev)
- @@ -613,37 +609,19 @@ static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev)
- if (ret)
- goto err_free_machine;
- - machine->cdc_en = regulator_get(NULL, "cdc_en");
- - if (WARN_ON(IS_ERR(machine->cdc_en))) {
- - dev_err(&pdev->dev, "Couldn't get regulator cdc_en: %ld\n",
- - PTR_ERR(machine->cdc_en));
- - machine->cdc_en = 0;
- - } else {
- - regulator_enable(machine->cdc_en);
- - }
- - machine->spk_reg = regulator_get(&pdev->dev, "vdd_spk_amp");
- - if (IS_ERR(machine->spk_reg)) {
- - dev_info(&pdev->dev, "No speaker regulator found\n");
- - machine->spk_reg = 0;
- - }
- -#ifdef CONFIG_SWITCH
- /* Addd h2w swith class support */
- - ret = switch_dev_register(&tegra_rt5640_headset_switch);
- - if (ret < 0)
- - goto err_fini_utils;
- -#endif
- card->dev = &pdev->dev;
- platform_set_drvdata(pdev, card);
- snd_soc_card_set_drvdata(card, machine);
- -
- + card->dapm.idle_bias_off = 1;
- ret = snd_soc_register_card(card);
- if (ret) {
- dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
- ret);
- - goto err_unregister_switch;
- + goto err_fini_utils;
- }
- if (!card->instantiated) {
- @@ -657,11 +635,7 @@ static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev)
- err_unregister_card:
- snd_soc_unregister_card(card);
- -err_unregister_switch:
- -#ifdef CONFIG_SWITCH
- - switch_dev_unregister(&tegra_rt5640_headset_switch);
- err_fini_utils:
- -#endif
- tegra_asoc_utils_fini(&machine->util_data);
- err_free_machine:
- kfree(machine);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement