summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/rt5645.c239
-rw-r--r--sound/soc/codecs/rt5645.h87
-rw-r--r--sound/soc/codecs/rt5670.c121
-rw-r--r--sound/soc/codecs/rt5670.h80
-rw-r--r--sound/soc/intel/Kconfig15
-rw-r--r--sound/soc/intel/Makefile2
-rw-r--r--sound/soc/intel/broadwell.c10
-rw-r--r--sound/soc/intel/byt-rt5640.c12
-rw-r--r--sound/soc/intel/bytcr_dpcm_rt5640.c1
-rw-r--r--sound/soc/intel/cht_bsw_rt5645.c327
-rw-r--r--sound/soc/intel/cht_bsw_rt5672.c15
-rw-r--r--sound/soc/intel/sst-baytrail-pcm.c6
-rw-r--r--sound/soc/intel/sst-dsp.c3
-rw-r--r--sound/soc/intel/sst-firmware.c3
-rw-r--r--sound/soc/intel/sst-haswell-dsp.c17
-rw-r--r--sound/soc/intel/sst-haswell-ipc.c5
-rw-r--r--sound/soc/intel/sst-haswell-pcm.c167
-rw-r--r--sound/soc/intel/sst-mfld-platform-pcm.c7
-rw-r--r--sound/soc/intel/sst/sst_acpi.c7
-rw-r--r--sound/soc/intel/sst/sst_loader.c3
20 files changed, 908 insertions, 219 deletions
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 27141e2df878..debf16c5b549 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -31,6 +31,7 @@
#include "rt5645.h"
#define RT5645_DEVICE_ID 0x6308
+#define RT5650_DEVICE_ID 0x6419
#define RT5645_PR_RANGE_BASE (0xff + 1)
#define RT5645_PR_SPACING 0x100
@@ -59,6 +60,10 @@ static const struct reg_default init_list[] = {
};
#define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list)
+static const struct reg_default rt5650_init_list[] = {
+ {0xf6, 0x0100},
+};
+
static const struct reg_default rt5645_reg[] = {
{ 0x00, 0x0000 },
{ 0x01, 0xc8c8 },
@@ -86,6 +91,7 @@ static const struct reg_default rt5645_reg[] = {
{ 0x2a, 0x5656 },
{ 0x2b, 0x5454 },
{ 0x2c, 0xaaa0 },
+ { 0x2d, 0x0000 },
{ 0x2f, 0x1002 },
{ 0x31, 0x5000 },
{ 0x32, 0x0000 },
@@ -193,6 +199,8 @@ static const struct reg_default rt5645_reg[] = {
{ 0xdb, 0x0003 },
{ 0xdc, 0x0049 },
{ 0xdd, 0x001b },
+ { 0xdf, 0x0008 },
+ { 0xe0, 0x4000 },
{ 0xe6, 0x8000 },
{ 0xe7, 0x0200 },
{ 0xec, 0xb300 },
@@ -242,6 +250,7 @@ static bool rt5645_volatile_register(struct device *dev, unsigned int reg)
case RT5645_IRQ_CTRL3:
case RT5645_INT_IRQ_ST:
case RT5645_IL_CMD:
+ case RT5650_4BTN_IL_CMD1:
case RT5645_VENDOR_ID:
case RT5645_VENDOR_ID1:
case RT5645_VENDOR_ID2:
@@ -287,6 +296,7 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg)
case RT5645_STO_DAC_MIXER:
case RT5645_MONO_DAC_MIXER:
case RT5645_DIG_MIXER:
+ case RT5650_A_DAC_SOUR:
case RT5645_DIG_INF1_DATA:
case RT5645_PDM_OUT_CTRL:
case RT5645_REC_L1_MIXER:
@@ -378,6 +388,8 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg)
case RT5645_IL_CMD:
case RT5645_IL_CMD2:
case RT5645_IL_CMD3:
+ case RT5650_4BTN_IL_CMD1:
+ case RT5650_4BTN_IL_CMD2:
case RT5645_DRC1_HL_CTRL1:
case RT5645_DRC2_HL_CTRL1:
case RT5645_ADC_MONO_HP_CTRL1:
@@ -601,6 +613,87 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
}
+/**
+ * rt5645_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @codec: SoC audio codec device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5645 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec,
+ unsigned int filter_mask, unsigned int clk_src)
+{
+ unsigned int asrc2_mask = 0;
+ unsigned int asrc2_value = 0;
+ unsigned int asrc3_mask = 0;
+ unsigned int asrc3_value = 0;
+
+ switch (clk_src) {
+ case RT5645_CLK_SEL_SYS:
+ case RT5645_CLK_SEL_I2S1_ASRC:
+ case RT5645_CLK_SEL_I2S2_ASRC:
+ case RT5645_CLK_SEL_SYS2:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (filter_mask & RT5645_DA_STEREO_FILTER) {
+ asrc2_mask |= RT5645_DA_STO_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5645_DA_STO_CLK_SEL_MASK)
+ | (clk_src << RT5645_DA_STO_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5645_DA_MONO_L_FILTER) {
+ asrc2_mask |= RT5645_DA_MONOL_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5645_DA_MONOL_CLK_SEL_MASK)
+ | (clk_src << RT5645_DA_MONOL_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5645_DA_MONO_R_FILTER) {
+ asrc2_mask |= RT5645_DA_MONOR_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5645_DA_MONOR_CLK_SEL_MASK)
+ | (clk_src << RT5645_DA_MONOR_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5645_AD_STEREO_FILTER) {
+ asrc2_mask |= RT5645_AD_STO1_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5645_AD_STO1_CLK_SEL_MASK)
+ | (clk_src << RT5645_AD_STO1_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5645_AD_MONO_L_FILTER) {
+ asrc3_mask |= RT5645_AD_MONOL_CLK_SEL_MASK;
+ asrc3_value = (asrc3_value & ~RT5645_AD_MONOL_CLK_SEL_MASK)
+ | (clk_src << RT5645_AD_MONOL_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5645_AD_MONO_R_FILTER) {
+ asrc3_mask |= RT5645_AD_MONOR_CLK_SEL_MASK;
+ asrc3_value = (asrc3_value & ~RT5645_AD_MONOR_CLK_SEL_MASK)
+ | (clk_src << RT5645_AD_MONOR_CLK_SEL_SFT);
+ }
+
+ if (asrc2_mask)
+ snd_soc_update_bits(codec, RT5645_ASRC_2,
+ asrc2_mask, asrc2_value);
+
+ if (asrc3_mask)
+ snd_soc_update_bits(codec, RT5645_ASRC_3,
+ asrc3_mask, asrc3_value);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt5645_sel_asrc_clk_src);
+
/* Digital Mixer */
static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = {
SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER,
@@ -1007,6 +1100,44 @@ static SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5645_if1_adc_in_mux =
SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum);
+/* MX-2d [3] [2] */
+static const char * const rt5650_a_dac1_src[] = {
+ "DAC1", "Stereo DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5650_a_dac1_l_enum, RT5650_A_DAC_SOUR,
+ RT5650_A_DAC1_L_IN_SFT, rt5650_a_dac1_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac1_l_mux =
+ SOC_DAPM_ENUM("A DAC1 L source", rt5650_a_dac1_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5650_a_dac1_r_enum, RT5650_A_DAC_SOUR,
+ RT5650_A_DAC1_R_IN_SFT, rt5650_a_dac1_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac1_r_mux =
+ SOC_DAPM_ENUM("A DAC1 R source", rt5650_a_dac1_r_enum);
+
+/* MX-2d [1] [0] */
+static const char * const rt5650_a_dac2_src[] = {
+ "Stereo DAC Mixer", "Mono DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5650_a_dac2_l_enum, RT5650_A_DAC_SOUR,
+ RT5650_A_DAC2_L_IN_SFT, rt5650_a_dac2_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac2_l_mux =
+ SOC_DAPM_ENUM("A DAC2 L source", rt5650_a_dac2_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5650_a_dac2_r_enum, RT5650_A_DAC_SOUR,
+ RT5650_A_DAC2_R_IN_SFT, rt5650_a_dac2_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac2_r_mux =
+ SOC_DAPM_ENUM("A DAC2 R source", rt5650_a_dac2_r_enum);
+
/* MX-2F [13:12] */
static const char * const rt5645_if2_adc_in_src[] = {
"IF_ADC1", "IF_ADC2", "VAD_ADC"
@@ -1151,11 +1282,16 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
hp_amp_power(codec, 1);
/* headphone unmute sequence */
- snd_soc_update_bits(codec, RT5645_DEPOP_M3, RT5645_CP_FQ1_MASK |
- RT5645_CP_FQ2_MASK | RT5645_CP_FQ3_MASK,
- (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
- (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
- (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
+ if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+ snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+ } else {
+ snd_soc_update_bits(codec, RT5645_DEPOP_M3,
+ RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
+ RT5645_CP_FQ3_MASK,
+ (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
+ (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
+ (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
+ }
regmap_write(rt5645->regmap,
RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
snd_soc_update_bits(codec, RT5645_DEPOP_M1,
@@ -1175,12 +1311,16 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_PRE_PMD:
/* headphone mute sequence */
- snd_soc_update_bits(codec, RT5645_DEPOP_M3,
- RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
- RT5645_CP_FQ3_MASK,
- (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
- (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
- (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
+ if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+ snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+ } else {
+ snd_soc_update_bits(codec, RT5645_DEPOP_M3,
+ RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
+ RT5645_CP_FQ3_MASK,
+ (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
+ (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
+ (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
+ }
regmap_write(rt5645->regmap,
RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
snd_soc_update_bits(codec, RT5645_DEPOP_M1,
@@ -1574,6 +1714,17 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("SPOR"),
};
+static const struct snd_soc_dapm_widget rt5650_specific_dapm_widgets[] = {
+ SND_SOC_DAPM_MUX("A DAC1 L Mux", SND_SOC_NOPM,
+ 0, 0, &rt5650_a_dac1_l_mux),
+ SND_SOC_DAPM_MUX("A DAC1 R Mux", SND_SOC_NOPM,
+ 0, 0, &rt5650_a_dac1_r_mux),
+ SND_SOC_DAPM_MUX("A DAC2 L Mux", SND_SOC_NOPM,
+ 0, 0, &rt5650_a_dac2_l_mux),
+ SND_SOC_DAPM_MUX("A DAC2 R Mux", SND_SOC_NOPM,
+ 0, 0, &rt5650_a_dac2_r_mux),
+};
+
static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
{ "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc },
{ "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc },
@@ -1779,13 +1930,9 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
{ "DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" },
{ "DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" },
- { "DAC L1", NULL, "Stereo DAC MIXL" },
{ "DAC L1", NULL, "PLL1", is_sys_clk_from_pll },
- { "DAC R1", NULL, "Stereo DAC MIXR" },
{ "DAC R1", NULL, "PLL1", is_sys_clk_from_pll },
- { "DAC L2", NULL, "Mono DAC MIXL" },
{ "DAC L2", NULL, "PLL1", is_sys_clk_from_pll },
- { "DAC R2", NULL, "Mono DAC MIXR" },
{ "DAC R2", NULL, "PLL1", is_sys_clk_from_pll },
{ "SPK MIXL", "BST1 Switch", "BST1" },
@@ -1874,6 +2021,30 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
{ "SPOR", NULL, "SPK amp" },
};
+static const struct snd_soc_dapm_route rt5650_specific_dapm_routes[] = {
+ { "A DAC1 L Mux", "DAC1", "DAC1 MIXL"},
+ { "A DAC1 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"},
+ { "A DAC1 R Mux", "DAC1", "DAC1 MIXR"},
+ { "A DAC1 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"},
+
+ { "A DAC2 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"},
+ { "A DAC2 L Mux", "Mono DAC Mixer", "Mono DAC MIXL"},
+ { "A DAC2 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"},
+ { "A DAC2 R Mux", "Mono DAC Mixer", "Mono DAC MIXR"},
+
+ { "DAC L1", NULL, "A DAC1 L Mux" },
+ { "DAC R1", NULL, "A DAC1 R Mux" },
+ { "DAC L2", NULL, "A DAC2 L Mux" },
+ { "DAC R2", NULL, "A DAC2 R Mux" },
+};
+
+static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = {
+ { "DAC L1", NULL, "Stereo DAC MIXL" },
+ { "DAC R1", NULL, "Stereo DAC MIXR" },
+ { "DAC L2", NULL, "Mono DAC MIXL" },
+ { "DAC R2", NULL, "Mono DAC MIXR" },
+};
+
static int rt5645_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
@@ -2293,6 +2464,22 @@ static int rt5645_probe(struct snd_soc_codec *codec)
rt5645->codec = codec;
+ switch (rt5645->codec_type) {
+ case CODEC_TYPE_RT5645:
+ snd_soc_dapm_add_routes(&codec->dapm,
+ rt5645_specific_dapm_routes,
+ ARRAY_SIZE(rt5645_specific_dapm_routes));
+ break;
+ case CODEC_TYPE_RT5650:
+ snd_soc_dapm_new_controls(&codec->dapm,
+ rt5650_specific_dapm_widgets,
+ ARRAY_SIZE(rt5650_specific_dapm_widgets));
+ snd_soc_dapm_add_routes(&codec->dapm,
+ rt5650_specific_dapm_routes,
+ ARRAY_SIZE(rt5650_specific_dapm_routes));
+ break;
+ }
+
rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
@@ -2424,6 +2611,7 @@ static const struct regmap_config rt5645_regmap = {
static const struct i2c_device_id rt5645_i2c_id[] = {
{ "rt5645", 0 },
+ { "rt5650", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
@@ -2456,9 +2644,18 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
}
regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val);
- if (val != RT5645_DEVICE_ID) {
+
+ switch (val) {
+ case RT5645_DEVICE_ID:
+ rt5645->codec_type = CODEC_TYPE_RT5645;
+ break;
+ case RT5650_DEVICE_ID:
+ rt5645->codec_type = CODEC_TYPE_RT5650;
+ break;
+ default:
dev_err(&i2c->dev,
- "Device with ID register %x is not rt5645\n", val);
+ "Device with ID register %x is not rt5645 or rt5650\n",
+ val);
return -ENODEV;
}
@@ -2469,6 +2666,14 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
if (ret != 0)
dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+ if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+ ret = regmap_register_patch(rt5645->regmap, rt5650_init_list,
+ ARRAY_SIZE(rt5650_init_list));
+ if (ret != 0)
+ dev_warn(&i2c->dev, "Apply rt5650 patch failed: %d\n",
+ ret);
+ }
+
if (rt5645->pdata.in2_diff)
regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL,
RT5645_IN_DF2, RT5645_IN_DF2);
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
index a815e36a2bdb..dbfd98c22f4d 100644
--- a/sound/soc/codecs/rt5645.h
+++ b/sound/soc/codecs/rt5645.h
@@ -47,6 +47,7 @@
#define RT5645_STO_DAC_MIXER 0x2a
#define RT5645_MONO_DAC_MIXER 0x2b
#define RT5645_DIG_MIXER 0x2c
+#define RT5650_A_DAC_SOUR 0x2d
#define RT5645_DIG_INF1_DATA 0x2f
/* Mixer - PDM */
#define RT5645_PDM_OUT_CTRL 0x31
@@ -150,6 +151,8 @@
#define RT5645_IL_CMD 0xdb
#define RT5645_IL_CMD2 0xdc
#define RT5645_IL_CMD3 0xdd
+#define RT5650_4BTN_IL_CMD1 0xdf
+#define RT5650_4BTN_IL_CMD2 0xe0
#define RT5645_DRC1_HL_CTRL1 0xe7
#define RT5645_DRC2_HL_CTRL1 0xe9
#define RT5645_MUTI_DRC_CTRL1 0xea
@@ -472,6 +475,12 @@
#define RT5645_DAC_L2_DAC_R_VOL_MASK (0x1 << 4)
#define RT5645_DAC_L2_DAC_R_VOL_SFT 4
+/* Analog DAC1/2 Input Source Control (0x2d) */
+#define RT5650_A_DAC1_L_IN_SFT 3
+#define RT5650_A_DAC1_R_IN_SFT 2
+#define RT5650_A_DAC2_L_IN_SFT 1
+#define RT5650_A_DAC2_R_IN_SFT 0
+
/* Digital Interface Data Control (0x2f) */
#define RT5645_IF1_ADC2_IN_SEL (0x1 << 15)
#define RT5645_IF1_ADC2_IN_SFT 15
@@ -1111,50 +1120,27 @@
#define RT5645_DMIC_2_M_NOR (0x0 << 8)
#define RT5645_DMIC_2_M_ASYN (0x1 << 8)
+/* ASRC clock source selection (0x84, 0x85) */
+#define RT5645_CLK_SEL_SYS (0x0)
+#define RT5645_CLK_SEL_I2S1_ASRC (0x1)
+#define RT5645_CLK_SEL_I2S2_ASRC (0x2)
+#define RT5645_CLK_SEL_SYS2 (0x5)
+
/* ASRC Control 2 (0x84) */
-#define RT5645_MDA_L_M_MASK (0x1 << 15)
-#define RT5645_MDA_L_M_SFT 15
-#define RT5645_MDA_L_M_NOR (0x0 << 15)
-#define RT5645_MDA_L_M_ASYN (0x1 << 15)
-#define RT5645_MDA_R_M_MASK (0x1 << 14)
-#define RT5645_MDA_R_M_SFT 14
-#define RT5645_MDA_R_M_NOR (0x0 << 14)
-#define RT5645_MDA_R_M_ASYN (0x1 << 14)
-#define RT5645_MAD_L_M_MASK (0x1 << 13)
-#define RT5645_MAD_L_M_SFT 13
-#define RT5645_MAD_L_M_NOR (0x0 << 13)
-#define RT5645_MAD_L_M_ASYN (0x1 << 13)
-#define RT5645_MAD_R_M_MASK (0x1 << 12)
-#define RT5645_MAD_R_M_SFT 12
-#define RT5645_MAD_R_M_NOR (0x0 << 12)
-#define RT5645_MAD_R_M_ASYN (0x1 << 12)
-#define RT5645_ADC_M_MASK (0x1 << 11)
-#define RT5645_ADC_M_SFT 11
-#define RT5645_ADC_M_NOR (0x0 << 11)
-#define RT5645_ADC_M_ASYN (0x1 << 11)
-#define RT5645_STO_DAC_M_MASK (0x1 << 5)
-#define RT5645_STO_DAC_M_SFT 5
-#define RT5645_STO_DAC_M_NOR (0x0 << 5)
-#define RT5645_STO_DAC_M_ASYN (0x1 << 5)
-#define RT5645_I2S1_R_D_MASK (0x1 << 4)
-#define RT5645_I2S1_R_D_SFT 4
-#define RT5645_I2S1_R_D_DIS (0x0 << 4)
-#define RT5645_I2S1_R_D_EN (0x1 << 4)
-#define RT5645_I2S2_R_D_MASK (0x1 << 3)
-#define RT5645_I2S2_R_D_SFT 3
-#define RT5645_I2S2_R_D_DIS (0x0 << 3)
-#define RT5645_I2S2_R_D_EN (0x1 << 3)
-#define RT5645_PRE_SCLK_MASK (0x3)
-#define RT5645_PRE_SCLK_SFT 0
-#define RT5645_PRE_SCLK_512 (0x0)
-#define RT5645_PRE_SCLK_1024 (0x1)
-#define RT5645_PRE_SCLK_2048 (0x2)
+#define RT5645_DA_STO_CLK_SEL_MASK (0xf << 12)
+#define RT5645_DA_STO_CLK_SEL_SFT 12
+#define RT5645_DA_MONOL_CLK_SEL_MASK (0xf << 8)
+#define RT5645_DA_MONOL_CLK_SEL_SFT 8
+#define RT5645_DA_MONOR_CLK_SEL_MASK (0xf << 4)
+#define RT5645_DA_MONOR_CLK_SEL_SFT 4
+#define RT5645_AD_STO1_CLK_SEL_MASK (0xf << 0)
+#define RT5645_AD_STO1_CLK_SEL_SFT 0
/* ASRC Control 3 (0x85) */
-#define RT5645_I2S1_RATE_MASK (0xf << 12)
-#define RT5645_I2S1_RATE_SFT 12
-#define RT5645_I2S2_RATE_MASK (0xf << 8)
-#define RT5645_I2S2_RATE_SFT 8
+#define RT5645_AD_MONOL_CLK_SEL_MASK (0xf << 4)
+#define RT5645_AD_MONOL_CLK_SEL_SFT 4
+#define RT5645_AD_MONOR_CLK_SEL_MASK (0xf << 0)
+#define RT5645_AD_MONOR_CLK_SEL_SFT 0
/* ASRC Control 4 (0x89) */
#define RT5645_I2S1_PD_MASK (0x7 << 12)
@@ -2175,6 +2161,24 @@ enum {
RT5645_DMIC_DATA_GPIO11,
};
+enum {
+ CODEC_TYPE_RT5645,
+ CODEC_TYPE_RT5650,
+};
+
+/* filter mask */
+enum {
+ RT5645_DA_STEREO_FILTER = 0x1,
+ RT5645_DA_MONO_L_FILTER = (0x1 << 1),
+ RT5645_DA_MONO_R_FILTER = (0x1 << 2),
+ RT5645_AD_STEREO_FILTER = (0x1 << 3),
+ RT5645_AD_MONO_L_FILTER = (0x1 << 4),
+ RT5645_AD_MONO_R_FILTER = (0x1 << 5),
+};
+
+int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec,
+ unsigned int filter_mask, unsigned int clk_src);
+
struct rt5645_priv {
struct snd_soc_codec *codec;
struct rt5645_platform_data pdata;
@@ -2184,6 +2188,7 @@ struct rt5645_priv {
struct snd_soc_jack *mic_jack;
struct delayed_work jack_detect_work;
+ int codec_type;
int sysclk;
int sysclk_src;
int lrck[RT5645_AIFS];
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index 8a0833de1665..0632b7458a53 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -14,10 +14,12 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
+#include <linux/pm_runtime.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h>
+#include <linux/dmi.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -588,6 +590,89 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source,
return 0;
}
+
+/**
+ * rt5670_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @codec: SoC audio codec device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5670 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec,
+ unsigned int filter_mask, unsigned int clk_src)
+{
+ unsigned int asrc2_mask = 0, asrc2_value = 0;
+ unsigned int asrc3_mask = 0, asrc3_value = 0;
+
+ if (clk_src > RT5670_CLK_SEL_SYS3)
+ return -EINVAL;
+
+ if (filter_mask & RT5670_DA_STEREO_FILTER) {
+ asrc2_mask |= RT5670_DA_STO_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5670_DA_STO_CLK_SEL_MASK)
+ | (clk_src << RT5670_DA_STO_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5670_DA_MONO_L_FILTER) {
+ asrc2_mask |= RT5670_DA_MONOL_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5670_DA_MONOL_CLK_SEL_MASK)
+ | (clk_src << RT5670_DA_MONOL_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5670_DA_MONO_R_FILTER) {
+ asrc2_mask |= RT5670_DA_MONOR_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5670_DA_MONOR_CLK_SEL_MASK)
+ | (clk_src << RT5670_DA_MONOR_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5670_AD_STEREO_FILTER) {
+ asrc2_mask |= RT5670_AD_STO1_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5670_AD_STO1_CLK_SEL_MASK)
+ | (clk_src << RT5670_AD_STO1_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5670_AD_MONO_L_FILTER) {
+ asrc3_mask |= RT5670_AD_MONOL_CLK_SEL_MASK;
+ asrc3_value = (asrc3_value & ~RT5670_AD_MONOL_CLK_SEL_MASK)
+ | (clk_src << RT5670_AD_MONOL_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5670_AD_MONO_R_FILTER) {
+ asrc3_mask |= RT5670_AD_MONOR_CLK_SEL_MASK;
+ asrc3_value = (asrc3_value & ~RT5670_AD_MONOR_CLK_SEL_MASK)
+ | (clk_src << RT5670_AD_MONOR_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5670_UP_RATE_FILTER) {
+ asrc3_mask |= RT5670_UP_CLK_SEL_MASK;
+ asrc3_value = (asrc3_value & ~RT5670_UP_CLK_SEL_MASK)
+ | (clk_src << RT5670_UP_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5670_DOWN_RATE_FILTER) {
+ asrc3_mask |= RT5670_DOWN_CLK_SEL_MASK;
+ asrc3_value = (asrc3_value & ~RT5670_DOWN_CLK_SEL_MASK)
+ | (clk_src << RT5670_DOWN_CLK_SEL_SFT);
+ }
+
+ if (asrc2_mask)
+ snd_soc_update_bits(codec, RT5670_ASRC_2,
+ asrc2_mask, asrc2_value);
+
+ if (asrc3_mask)
+ snd_soc_update_bits(codec, RT5670_ASRC_3,
+ asrc3_mask, asrc3_value);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt5670_sel_asrc_clk_src);
+
/* Digital Mixer */
static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = {
SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER,
@@ -2188,6 +2273,13 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai,
if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src)
return 0;
+ if (rt5670->pdata.jd_mode) {
+ if (clk_id == RT5670_SCLK_S_PLL1)
+ snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
+ else
+ snd_soc_dapm_disable_pin(&codec->dapm, "PLL1");
+ snd_soc_dapm_sync(&codec->dapm);
+ }
switch (clk_id) {
case RT5670_SCLK_S_MCLK:
reg_val |= RT5670_SCLK_SRC_MCLK;
@@ -2549,6 +2641,17 @@ static struct acpi_device_id rt5670_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
#endif
+static const struct dmi_system_id dmi_platform_intel_braswell[] = {
+ {
+ .ident = "Intel Braswell",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"),
+ },
+ },
+ {}
+};
+
static int rt5670_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -2568,6 +2671,12 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
if (pdata)
rt5670->pdata = *pdata;
+ if (dmi_check_system(dmi_platform_intel_braswell)) {
+ rt5670->pdata.dmic_en = true;
+ rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
+ rt5670->pdata.jd_mode = 1;
+ }
+
rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap);
if (IS_ERR(rt5670->regmap)) {
ret = PTR_ERR(rt5670->regmap);
@@ -2609,6 +2718,10 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
}
if (rt5670->pdata.jd_mode) {
+ regmap_update_bits(rt5670->regmap, RT5670_GLB_CLK,
+ RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_RCCLK);
+ rt5670->sysclk = 0;
+ rt5670->sysclk_src = RT5670_SCLK_S_RCCLK;
regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1,
RT5670_PWR_MB, RT5670_PWR_MB);
regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG2,
@@ -2716,18 +2829,26 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
}
+ pm_runtime_enable(&i2c->dev);
+ pm_request_idle(&i2c->dev);
+
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5670,
rt5670_dai, ARRAY_SIZE(rt5670_dai));
if (ret < 0)
goto err;
+ pm_runtime_put(&i2c->dev);
+
return 0;
err:
+ pm_runtime_disable(&i2c->dev);
+
return ret;
}
static int rt5670_i2c_remove(struct i2c_client *i2c)
{
+ pm_runtime_disable(&i2c->dev);
snd_soc_unregister_codec(&i2c->dev);
return 0;
diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h
index d11b9c207e26..21f8e18c13c4 100644
--- a/sound/soc/codecs/rt5670.h
+++ b/sound/soc/codecs/rt5670.h
@@ -1023,50 +1023,33 @@
#define RT5670_DMIC_2_M_NOR (0x0 << 8)
#define RT5670_DMIC_2_M_ASYN (0x1 << 8)
+/* ASRC clock source selection (0x84, 0x85) */
+#define RT5670_CLK_SEL_SYS (0x0)
+#define RT5670_CLK_SEL_I2S1_ASRC (0x1)
+#define RT5670_CLK_SEL_I2S2_ASRC (0x2)
+#define RT5670_CLK_SEL_I2S3_ASRC (0x3)
+#define RT5670_CLK_SEL_SYS2 (0x5)
+#define RT5670_CLK_SEL_SYS3 (0x6)
+
/* ASRC Control 2 (0x84) */
-#define RT5670_MDA_L_M_MASK (0x1 << 15)
-#define RT5670_MDA_L_M_SFT 15
-#define RT5670_MDA_L_M_NOR (0x0 << 15)
-#define RT5670_MDA_L_M_ASYN (0x1 << 15)
-#define RT5670_MDA_R_M_MASK (0x1 << 14)
-#define RT5670_MDA_R_M_SFT 14
-#define RT5670_MDA_R_M_NOR (0x0 << 14)
-#define RT5670_MDA_R_M_ASYN (0x1 << 14)
-#define RT5670_MAD_L_M_MASK (0x1 << 13)
-#define RT5670_MAD_L_M_SFT 13
-#define RT5670_MAD_L_M_NOR (0x0 << 13)
-#define RT5670_MAD_L_M_ASYN (0x1 << 13)
-#define RT5670_MAD_R_M_MASK (0x1 << 12)
-#define RT5670_MAD_R_M_SFT 12
-#define RT5670_MAD_R_M_NOR (0x0 << 12)
-#define RT5670_MAD_R_M_ASYN (0x1 << 12)
-#define RT5670_ADC_M_MASK (0x1 << 11)
-#define RT5670_ADC_M_SFT 11
-#define RT5670_ADC_M_NOR (0x0 << 11)
-#define RT5670_ADC_M_ASYN (0x1 << 11)
-#define RT5670_STO_DAC_M_MASK (0x1 << 5)
-#define RT5670_STO_DAC_M_SFT 5
-#define RT5670_STO_DAC_M_NOR (0x0 << 5)
-#define RT5670_STO_DAC_M_ASYN (0x1 << 5)
-#define RT5670_I2S1_R_D_MASK (0x1 << 4)
-#define RT5670_I2S1_R_D_SFT 4
-#define RT5670_I2S1_R_D_DIS (0x0 << 4)
-#define RT5670_I2S1_R_D_EN (0x1 << 4)
-#define RT5670_I2S2_R_D_MASK (0x1 << 3)
-#define RT5670_I2S2_R_D_SFT 3
-#define RT5670_I2S2_R_D_DIS (0x0 << 3)
-#define RT5670_I2S2_R_D_EN (0x1 << 3)
-#define RT5670_PRE_SCLK_MASK (0x3)
-#define RT5670_PRE_SCLK_SFT 0
-#define RT5670_PRE_SCLK_512 (0x0)
-#define RT5670_PRE_SCLK_1024 (0x1)
-#define RT5670_PRE_SCLK_2048 (0x2)
+#define RT5670_DA_STO_CLK_SEL_MASK (0xf << 12)
+#define RT5670_DA_STO_CLK_SEL_SFT 12
+#define RT5670_DA_MONOL_CLK_SEL_MASK (0xf << 8)
+#define RT5670_DA_MONOL_CLK_SEL_SFT 8
+#define RT5670_DA_MONOR_CLK_SEL_MASK (0xf << 4)
+#define RT5670_DA_MONOR_CLK_SEL_SFT 4
+#define RT5670_AD_STO1_CLK_SEL_MASK (0xf << 0)
+#define RT5670_AD_STO1_CLK_SEL_SFT 0
/* ASRC Control 3 (0x85) */
-#define RT5670_I2S1_RATE_MASK (0xf << 12)
-#define RT5670_I2S1_RATE_SFT 12
-#define RT5670_I2S2_RATE_MASK (0xf << 8)
-#define RT5670_I2S2_RATE_SFT 8
+#define RT5670_UP_CLK_SEL_MASK (0xf << 12)
+#define RT5670_UP_CLK_SEL_SFT 12
+#define RT5670_DOWN_CLK_SEL_MASK (0xf << 8)
+#define RT5670_DOWN_CLK_SEL_SFT 8
+#define RT5670_AD_MONOL_CLK_SEL_MASK (0xf << 4)
+#define RT5670_AD_MONOL_CLK_SEL_SFT 4
+#define RT5670_AD_MONOR_CLK_SEL_MASK (0xf << 0)
+#define RT5670_AD_MONOR_CLK_SEL_SFT 0
/* ASRC Control 4 (0x89) */
#define RT5670_I2S1_PD_MASK (0x7 << 12)
@@ -1983,6 +1966,21 @@ enum {
RT5670_DMIC_DATA_GPIO5,
};
+/* filter mask */
+enum {
+ RT5670_DA_STEREO_FILTER = 0x1,
+ RT5670_DA_MONO_L_FILTER = (0x1 << 1),
+ RT5670_DA_MONO_R_FILTER = (0x1 << 2),
+ RT5670_AD_STEREO_FILTER = (0x1 << 3),
+ RT5670_AD_MONO_L_FILTER = (0x1 << 4),
+ RT5670_AD_MONO_R_FILTER = (0x1 << 5),
+ RT5670_UP_RATE_FILTER = (0x1 << 6),
+ RT5670_DOWN_RATE_FILTER = (0x1 << 7),
+};
+
+int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec,
+ unsigned int filter_mask, unsigned int clk_src);
+
struct rt5670_priv {
struct snd_soc_codec *codec;
struct rt5670_platform_data pdata;
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index f86de1211b96..ee03dbdda235 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -46,7 +46,7 @@ config SND_SOC_INTEL_BAYTRAIL
config SND_SOC_INTEL_HASWELL_MACH
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
- depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \\
+ depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \
I2C_DESIGNWARE_PLATFORM
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5640
@@ -76,7 +76,7 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH
config SND_SOC_INTEL_BROADWELL_MACH
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
- depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \\
+ depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \
I2C_DESIGNWARE_PLATFORM
select SND_SOC_INTEL_HASWELL
select SND_COMPRESS_OFFLOAD
@@ -110,3 +110,14 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
platforms with RT5672 audio codec.
Say Y if you have such a device
If unsure select "N".
+
+config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
+ tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645 codec"
+ depends on X86_INTEL_LPSS
+ select SND_SOC_RT5645
+ select SND_SST_MFLD_PLATFORM
+ select SND_SST_IPC_ACPI
+ help
+ This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
+ platforms with RT5645 audio codec.
+ If unsure select "N".
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index e928ec385300..a8e53c45c6b6 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -28,6 +28,7 @@ snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
snd-soc-sst-broadwell-objs := broadwell.o
snd-soc-sst-bytcr-dpcm-rt5640-objs := bytcr_dpcm_rt5640.o
snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
+snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
@@ -35,6 +36,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-dpcm-rt5640.o
obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
+obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o
# DSP driver
obj-$(CONFIG_SND_SST_IPC) += sst/
diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c
index 7cf95d5d5d80..9cf7d01479ad 100644
--- a/sound/soc/intel/broadwell.c
+++ b/sound/soc/intel/broadwell.c
@@ -140,8 +140,6 @@ static struct snd_soc_ops broadwell_rt286_ops = {
static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
struct sst_hsw *broadwell = pdata->dsp;
int ret;
@@ -155,14 +153,6 @@ static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- /* always connected - check HP for jack detect */
- snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_enable_pin(dapm, "Speaker");
- snd_soc_dapm_enable_pin(dapm, "Mic Jack");
- snd_soc_dapm_enable_pin(dapm, "Line Jack");
- snd_soc_dapm_enable_pin(dapm, "DMIC1");
- snd_soc_dapm_enable_pin(dapm, "DMIC2");
-
return 0;
}
diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c
index 0cba7830c5e9..354eaad886e1 100644
--- a/sound/soc/intel/byt-rt5640.c
+++ b/sound/soc/intel/byt-rt5640.c
@@ -132,7 +132,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
{
int ret;
struct snd_soc_codec *codec = runtime->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_card *card = runtime->card;
const struct snd_soc_dapm_route *custom_map;
int num_routes;
@@ -161,7 +160,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
}
- ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
+ ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
if (ret)
return ret;
@@ -171,13 +170,8 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
return ret;
}
- snd_soc_dapm_ignore_suspend(dapm, "HPOL");
- snd_soc_dapm_ignore_suspend(dapm, "HPOR");
-
- snd_soc_dapm_ignore_suspend(dapm, "SPOLP");
- snd_soc_dapm_ignore_suspend(dapm, "SPOLN");
- snd_soc_dapm_ignore_suspend(dapm, "SPORP");
- snd_soc_dapm_ignore_suspend(dapm, "SPORN");
+ snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
+ snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
return ret;
}
diff --git a/sound/soc/intel/bytcr_dpcm_rt5640.c b/sound/soc/intel/bytcr_dpcm_rt5640.c
index eef0c56ec32e..59308629043e 100644
--- a/sound/soc/intel/bytcr_dpcm_rt5640.c
+++ b/sound/soc/intel/bytcr_dpcm_rt5640.c
@@ -215,7 +215,6 @@ static int snd_byt_mc_probe(struct platform_device *pdev)
static struct platform_driver snd_byt_mc_driver = {
.driver = {
- .owner = THIS_MODULE,
.name = "bytt100_rt5640",
.pm = &snd_soc_pm_ops,
},
diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/cht_bsw_rt5645.c
new file mode 100644
index 000000000000..b6f8377b6e33
--- /dev/null
+++ b/sound/soc/intel/cht_bsw_rt5645.c
@@ -0,0 +1,327 @@
+/*
+ * cht-bsw-rt5645.c - ASoc Machine driver for Intel Cherryview-based platforms
+ * Cherrytrail and Braswell, with RT5645 codec.
+ *
+ * Copyright (C) 2015 Intel Corp
+ * Author: Fang, Yang A <yang.a.fang@intel.com>
+ * N,Harshapriya <harshapriya.n@intel.com>
+ * This file is modified from cht_bsw_rt5672.c
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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/platform_device.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../codecs/rt5645.h"
+#include "sst-atom-controls.h"
+
+#define CHT_PLAT_CLK_3_HZ 19200000
+#define CHT_CODEC_DAI "rt5645-aif1"
+
+struct cht_mc_private {
+ struct snd_soc_jack hp_jack;
+ struct snd_soc_jack mic_jack;
+};
+
+static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
+{
+ int i;
+
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_pcm_runtime *rtd;
+
+ rtd = card->rtd + i;
+ if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
+ strlen(CHT_CODEC_DAI)))
+ return rtd->codec_dai;
+ }
+ return NULL;
+}
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dai *codec_dai;
+ int ret;
+
+ codec_dai = cht_get_codec_dai(card);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
+ return -EIO;
+ }
+
+ if (!SND_SOC_DAPM_EVENT_OFF(event))
+ return 0;
+
+ /* Set codec sysclk source to its internal clock because codec PLL will
+ * be off when idle and MCLK will also be off by ACPI when codec is
+ * runtime suspended. Codec needs clock for jack detection and button
+ * press.
+ */
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK,
+ 0, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+ platform_clock_control, SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route cht_audio_map[] = {
+ {"IN1P", NULL, "Headset Mic"},
+ {"IN1N", NULL, "Headset Mic"},
+ {"DMIC L1", NULL, "Int Mic"},
+ {"DMIC R1", NULL, "Int Mic"},
+ {"Headphone", NULL, "HPOL"},
+ {"Headphone", NULL, "HPOR"},
+ {"Ext Spk", NULL, "SPOL"},
+ {"Ext Spk", NULL, "SPOR"},
+ {"AIF1 Playback", NULL, "ssp2 Tx"},
+ {"ssp2 Tx", NULL, "codec_out0"},
+ {"ssp2 Tx", NULL, "codec_out1"},
+ {"codec_in0", NULL, "ssp2 Rx" },
+ {"codec_in1", NULL, "ssp2 Rx" },
+ {"ssp2 Rx", NULL, "AIF1 Capture"},
+ {"Headphone", NULL, "Platform Clock"},
+ {"Headset Mic", NULL, "Platform Clock"},
+ {"Int Mic", NULL, "Platform Clock"},
+ {"Ext Spk", NULL, "Platform Clock"},
+};
+
+static const struct snd_kcontrol_new cht_mc_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Int Mic"),
+ SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int ret;
+
+ /* set codec PLL source to the 19.2MHz platform clock (MCLK) */
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT5645_PLL1_S_MCLK,
+ CHT_PLAT_CLK_3_HZ, params_rate(params) * 512);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_PLL1,
+ params_rate(params) * 512, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ int ret;
+ struct snd_soc_codec *codec = runtime->codec;
+ struct snd_soc_dai *codec_dai = runtime->codec_dai;
+ struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
+
+ /* Select clk_i2s1_asrc as ASRC clock source */
+ rt5645_sel_asrc_clk_src(codec,
+ RT5645_DA_STEREO_FILTER |
+ RT5645_DA_MONO_L_FILTER |
+ RT5645_DA_MONO_R_FILTER |
+ RT5645_AD_STEREO_FILTER,
+ RT5645_CLK_SEL_I2S1_ASRC);
+
+ /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
+ if (ret < 0) {
+ dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_jack_new(codec, "Headphone Jack",
+ SND_JACK_HEADPHONE,
+ &ctx->hp_jack);
+ if (ret) {
+ dev_err(runtime->dev, "HP jack creation failed %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_jack_new(codec, "Mic Jack",
+ SND_JACK_MICROPHONE,
+ &ctx->mic_jack);
+ if (ret) {
+ dev_err(runtime->dev, "Mic jack creation failed %d\n", ret);
+ return ret;
+ }
+
+ rt5645_set_jack_detect(codec, &ctx->hp_jack, &ctx->mic_jack);
+
+ return ret;
+}
+
+static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP2 to 24-bit */
+ snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
+ SNDRV_PCM_HW_PARAM_FIRST_MASK],
+ SNDRV_PCM_FORMAT_S24_LE);
+ return 0;
+}
+
+static unsigned int rates_48000[] = {
+ 48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_48000 = {
+ .count = ARRAY_SIZE(rates_48000),
+ .list = rates_48000,
+};
+
+static int cht_aif1_startup(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_48000);
+}
+
+static struct snd_soc_ops cht_aif1_ops = {
+ .startup = cht_aif1_startup,
+};
+
+static struct snd_soc_ops cht_be_ssp2_ops = {
+ .hw_params = cht_aif1_hw_params,
+};
+
+static struct snd_soc_dai_link cht_dailink[] = {
+ [MERR_DPCM_AUDIO] = {
+ .name = "Audio Port",
+ .stream_name = "Audio",
+ .cpu_dai_name = "media-cpu-dai",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .platform_name = "sst-mfld-platform",
+ .ignore_suspend = 1,
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ops = &cht_aif1_ops,
+ },
+ [MERR_DPCM_COMPR] = {
+ .name = "Compressed Port",
+ .stream_name = "Compress",
+ .cpu_dai_name = "compress-cpu-dai",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .platform_name = "sst-mfld-platform",
+ },
+ /* CODEC<->CODEC link */
+ /* back ends */
+ {
+ .name = "SSP2-Codec",
+ .be_id = 1,
+ .cpu_dai_name = "ssp2-port",
+ .platform_name = "sst-mfld-platform",
+ .no_pcm = 1,
+ .codec_dai_name = "rt5645-aif1",
+ .codec_name = "i2c-10EC5645:00",
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
+ | SND_SOC_DAIFMT_CBS_CFS,
+ .init = cht_codec_init,
+ .be_hw_params_fixup = cht_codec_fixup,
+ .ignore_suspend = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ops = &cht_be_ssp2_ops,
+ },
+};
+
+/* SoC card */
+static struct snd_soc_card snd_soc_card_cht = {
+ .name = "chtrt5645",
+ .dai_link = cht_dailink,
+ .num_links = ARRAY_SIZE(cht_dailink),
+ .dapm_widgets = cht_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
+ .dapm_routes = cht_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(cht_audio_map),
+ .controls = cht_mc_controls,
+ .num_controls = ARRAY_SIZE(cht_mc_controls),
+};
+
+static int snd_cht_mc_probe(struct platform_device *pdev)
+{
+ int ret_val = 0;
+ struct cht_mc_private *drv;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
+ if (!drv)
+ return -ENOMEM;
+
+ snd_soc_card_cht.dev = &pdev->dev;
+ snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
+ ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
+ if (ret_val) {
+ dev_err(&pdev->dev,
+ "snd_soc_register_card failed %d\n", ret_val);
+ return ret_val;
+ }
+ platform_set_drvdata(pdev, &snd_soc_card_cht);
+ return ret_val;
+}
+
+static struct platform_driver snd_cht_mc_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "cht-bsw-rt5645",
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = snd_cht_mc_probe,
+};
+
+module_platform_driver(snd_cht_mc_driver)
+
+MODULE_DESCRIPTION("ASoC Intel(R) Braswell Machine driver");
+MODULE_AUTHOR("Fang, Yang A,N,Harshapriya");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:cht-bsw-rt5645");
diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c
index 9b8b561171b7..ff016621583a 100644
--- a/sound/soc/intel/cht_bsw_rt5672.c
+++ b/sound/soc/intel/cht_bsw_rt5672.c
@@ -140,6 +140,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
{
int ret;
struct snd_soc_dai *codec_dai = runtime->codec_dai;
+ struct snd_soc_codec *codec = codec_dai->codec;
/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
@@ -148,6 +149,19 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
return ret;
}
+ /* Select codec ASRC clock source to track I2S1 clock, because codec
+ * is in slave mode and 100fs I2S format (BCLK = 100 * LRCLK) cannot
+ * be supported by RT5672. Otherwise, ASRC will be disabled and cause
+ * noise.
+ */
+ rt5670_sel_asrc_clk_src(codec,
+ RT5670_DA_STEREO_FILTER
+ | RT5670_DA_MONO_L_FILTER
+ | RT5670_DA_MONO_R_FILTER
+ | RT5670_AD_STEREO_FILTER
+ | RT5670_AD_MONO_L_FILTER
+ | RT5670_AD_MONO_R_FILTER,
+ RT5670_CLK_SEL_I2S1_ASRC);
return 0;
}
@@ -270,7 +284,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
static struct platform_driver snd_cht_mc_driver = {
.driver = {
- .owner = THIS_MODULE,
.name = "cht-bsw-rt5672",
.pm = &snd_soc_pm_ops,
},
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c
index 3bb6288d8b4d..224c49c9f135 100644
--- a/sound/soc/intel/sst-baytrail-pcm.c
+++ b/sound/soc/intel/sst-baytrail-pcm.c
@@ -320,11 +320,6 @@ static struct snd_pcm_ops sst_byt_pcm_ops = {
.mmap = sst_byt_pcm_mmap,
};
-static void sst_byt_pcm_free(struct snd_pcm *pcm)
-{
- snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_pcm *pcm = rtd->pcm;
@@ -403,7 +398,6 @@ static struct snd_soc_platform_driver byt_soc_platform = {
.remove = sst_byt_pcm_remove,
.ops = &sst_byt_pcm_ops,
.pcm_new = sst_byt_pcm_new,
- .pcm_free = sst_byt_pcm_free,
};
static const struct snd_soc_component_driver byt_dai_component = {
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c
index 86e410845670..64e94212d2d2 100644
--- a/sound/soc/intel/sst-dsp.c
+++ b/sound/soc/intel/sst-dsp.c
@@ -410,8 +410,7 @@ void sst_dsp_free(struct sst_dsp *sst)
if (sst->ops->free)
sst->ops->free(sst);
- if (sst->dma)
- sst_dma_free(sst->dma);
+ sst_dma_free(sst->dma);
}
EXPORT_SYMBOL_GPL(sst_dsp_free);
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c
index b3f9489794a6..5f71ef607a57 100644
--- a/sound/soc/intel/sst-firmware.c
+++ b/sound/soc/intel/sst-firmware.c
@@ -497,6 +497,7 @@ struct sst_module *sst_module_new(struct sst_fw *sst_fw,
sst_module->sst_fw = sst_fw;
sst_module->scratch_size = template->scratch_size;
sst_module->persistent_size = template->persistent_size;
+ sst_module->entry = template->entry;
INIT_LIST_HEAD(&sst_module->block_list);
INIT_LIST_HEAD(&sst_module->runtime_list);
@@ -790,6 +791,7 @@ int sst_module_alloc_blocks(struct sst_module *module)
struct sst_block_allocator ba;
int ret;
+ memset(&ba, 0, sizeof(ba));
ba.size = module->size;
ba.type = module->type;
ba.offset = module->offset;
@@ -863,6 +865,7 @@ int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime,
if (module->persistent_size == 0)
return 0;
+ memset(&ba, 0, sizeof(ba));
ba.size = module->persistent_size;
ba.type = SST_MEM_DRAM;
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c
index 57039b00efc2..c42ffae5fe9f 100644
--- a/sound/soc/intel/sst-haswell-dsp.c
+++ b/sound/soc/intel/sst-haswell-dsp.c
@@ -306,7 +306,7 @@ static void hsw_reset(struct sst_dsp *sst)
static int hsw_set_dsp_D0(struct sst_dsp *sst)
{
int tries = 10;
- u32 reg;
+ u32 reg, fw_dump_bit;
/* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
@@ -368,7 +368,9 @@ finish:
can't be accessed, please enable each block before accessing. */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK;
- writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
+ /* for D0, always enable the block(DSRAM[0]) used for FW dump */
+ fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT;
+ writel(reg & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0);
/* disable DMA finish function for SSP0 & SSP1 */
@@ -491,6 +493,7 @@ static const struct sst_sram_shift sram_shift[] = {
{SST_DEV_ID_LYNX_POINT, 6, 16}, /* lp */
{SST_DEV_ID_WILDCAT_POINT, 2, 12}, /* wpt */
};
+
static u32 hsw_block_get_bit(struct sst_mem_block *block)
{
u32 bit = 0, shift = 0, index;
@@ -587,7 +590,9 @@ static int hsw_block_disable(struct sst_mem_block *block)
val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
bit = hsw_block_get_bit(block);
- writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
+ /* don't disable DSRAM[0], keep it always enable for FW dump*/
+ if (bit != (1 << SST_VDRTCL0_DSRAMPGE_SHIFT))
+ writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
/* wait 18 DSP clock ticks */
udelay(10);
@@ -612,7 +617,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
const struct sst_adsp_memregion *region;
struct device *dev;
int ret = -ENODEV, i, j, region_count;
- u32 offset, size;
+ u32 offset, size, fw_dump_bit;
dev = sst->dma_dev;
@@ -669,9 +674,11 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
}
}
+ /* always enable the block(DSRAM[0]) used for FW dump */
+ fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT;
/* set default power gating control, enable power gating control for all blocks. that is,
can't be accessed, please enable each block before accessing. */
- writel(0xffffffff, sst->addr.pci_cfg + SST_VDRTCTL0);
+ writel(0xffffffff & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0);
return 0;
}
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c
index 8156cc1accb7..a282179a3064 100644
--- a/sound/soc/intel/sst-haswell-ipc.c
+++ b/sound/soc/intel/sst-haswell-ipc.c
@@ -94,6 +94,8 @@
/* Mailbox */
#define IPC_MAX_MAILBOX_BYTES 256
+#define INVALID_STREAM_HW_ID 0xffffffff
+
/* Global Message - Types and Replies */
enum ipc_glb_type {
IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */
@@ -275,7 +277,6 @@ struct sst_hsw {
/* FW config */
struct sst_hsw_ipc_fw_ready fw_ready;
struct sst_hsw_ipc_fw_version version;
- struct sst_module *scratch;
bool fw_done;
struct sst_fw *sst_fw;
@@ -1208,6 +1209,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
return NULL;
spin_lock_irqsave(&sst->spinlock, flags);
+ stream->reply.stream_hw_id = INVALID_STREAM_HW_ID;
list_add(&stream->node, &hsw->stream_list);
stream->notify_position = notify_position;
stream->pdata = data;
@@ -2132,7 +2134,6 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata)
dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE,
hsw->dx_context, hsw->dx_context_paddr);
sst_dsp_free(hsw->dsp);
- kfree(hsw->scratch);
kthread_stop(hsw->tx_thread);
kfree(hsw->msg);
}
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
index 619525200705..78fa01be57f2 100644
--- a/sound/soc/intel/sst-haswell-pcm.c
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -78,7 +78,6 @@ static const u32 volume_map[] = {
#define HSW_PCM_DAI_ID_OFFLOAD0 1
#define HSW_PCM_DAI_ID_OFFLOAD1 2
#define HSW_PCM_DAI_ID_LOOPBACK 3
-#define HSW_PCM_DAI_ID_CAPTURE 4
static const struct snd_pcm_hardware hsw_pcm_hardware = {
@@ -99,6 +98,7 @@ static const struct snd_pcm_hardware hsw_pcm_hardware = {
struct hsw_pcm_module_map {
int dai_id;
+ int stream;
enum sst_hsw_module_id mod_id;
};
@@ -119,8 +119,9 @@ struct hsw_pcm_data {
};
enum hsw_pm_state {
- HSW_PM_STATE_D3 = 0,
- HSW_PM_STATE_D0 = 1,
+ HSW_PM_STATE_D0 = 0,
+ HSW_PM_STATE_RTD3 = 1,
+ HSW_PM_STATE_D3 = 2,
};
/* private data for the driver */
@@ -135,7 +136,17 @@ struct hsw_priv_data {
struct snd_dma_buffer dmab[HSW_PCM_COUNT][2];
/* DAI data */
- struct hsw_pcm_data pcm[HSW_PCM_COUNT];
+ struct hsw_pcm_data pcm[HSW_PCM_COUNT][2];
+};
+
+
+/* static mappings between PCMs and modules - may be dynamic in future */
+static struct hsw_pcm_module_map mod_map[] = {
+ {HSW_PCM_DAI_ID_SYSTEM, 0, SST_HSW_MODULE_PCM_SYSTEM},
+ {HSW_PCM_DAI_ID_OFFLOAD0, 0, SST_HSW_MODULE_PCM},
+ {HSW_PCM_DAI_ID_OFFLOAD1, 0, SST_HSW_MODULE_PCM},
+ {HSW_PCM_DAI_ID_LOOPBACK, 1, SST_HSW_MODULE_PCM_REFERENCE},
+ {HSW_PCM_DAI_ID_SYSTEM, 1, SST_HSW_MODULE_PCM_CAPTURE},
};
static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data);
@@ -168,9 +179,14 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value;
struct hsw_priv_data *pdata =
snd_soc_platform_get_drvdata(platform);
- struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
+ struct hsw_pcm_data *pcm_data;
struct sst_hsw *hsw = pdata->hsw;
u32 volume;
+ int dai, stream;
+
+ dai = mod_map[mc->reg].dai_id;
+ stream = mod_map[mc->reg].stream;
+ pcm_data = &pdata->pcm[dai][stream];
mutex_lock(&pcm_data->mutex);
pm_runtime_get_sync(pdata->dev);
@@ -212,9 +228,14 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value;
struct hsw_priv_data *pdata =
snd_soc_platform_get_drvdata(platform);
- struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
+ struct hsw_pcm_data *pcm_data;
struct sst_hsw *hsw = pdata->hsw;
u32 volume;
+ int dai, stream;
+
+ dai = mod_map[mc->reg].dai_id;
+ stream = mod_map[mc->reg].stream;
+ pcm_data = &pdata->pcm[dai][stream];
mutex_lock(&pcm_data->mutex);
pm_runtime_get_sync(pdata->dev);
@@ -309,7 +330,7 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = {
ARRAY_SIZE(volume_map) - 1, 0,
hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
/* Mic Capture volume */
- SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 0, 0, 8,
+ SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8,
ARRAY_SIZE(volume_map) - 1, 0,
hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
};
@@ -353,7 +374,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
struct hsw_priv_data *pdata =
snd_soc_platform_get_drvdata(rtd->platform);
- struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct hsw_pcm_data *pcm_data;
struct sst_hsw *hsw = pdata->hsw;
struct sst_module *module_data;
struct sst_dsp *dsp;
@@ -362,7 +383,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
enum sst_hsw_stream_path_id path_id;
u32 rate, bits, map, pages, module_id;
u8 channels;
- int ret;
+ int ret, dai;
+
+ dai = mod_map[rtd->cpu_dai->id].dai_id;
+ pcm_data = &pdata->pcm[dai][substream->stream];
/* check if we are being called a subsequent time */
if (pcm_data->allocated) {
@@ -552,8 +576,12 @@ static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct hsw_priv_data *pdata =
snd_soc_platform_get_drvdata(rtd->platform);
- struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct hsw_pcm_data *pcm_data;
struct sst_hsw *hsw = pdata->hsw;
+ int dai;
+
+ dai = mod_map[rtd->cpu_dai->id].dai_id;
+ pcm_data = &pdata->pcm[dai][substream->stream];
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -597,11 +625,16 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct hsw_priv_data *pdata =
snd_soc_platform_get_drvdata(rtd->platform);
- struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct hsw_pcm_data *pcm_data;
struct sst_hsw *hsw = pdata->hsw;
snd_pcm_uframes_t offset;
uint64_t ppos;
- u32 position = sst_hsw_get_dsp_position(hsw, pcm_data->stream);
+ u32 position;
+ int dai;
+
+ dai = mod_map[rtd->cpu_dai->id].dai_id;
+ pcm_data = &pdata->pcm[dai][substream->stream];
+ position = sst_hsw_get_dsp_position(hsw, pcm_data->stream);
offset = bytes_to_frames(runtime, position);
ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream);
@@ -618,8 +651,10 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream)
snd_soc_platform_get_drvdata(rtd->platform);
struct hsw_pcm_data *pcm_data;
struct sst_hsw *hsw = pdata->hsw;
+ int dai;
- pcm_data = &pdata->pcm[rtd->cpu_dai->id];
+ dai = mod_map[rtd->cpu_dai->id].dai_id;
+ pcm_data = &pdata->pcm[dai][substream->stream];
mutex_lock(&pcm_data->mutex);
pm_runtime_get_sync(pdata->dev);
@@ -648,9 +683,12 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct hsw_priv_data *pdata =
snd_soc_platform_get_drvdata(rtd->platform);
- struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct hsw_pcm_data *pcm_data;
struct sst_hsw *hsw = pdata->hsw;
- int ret;
+ int ret, dai;
+
+ dai = mod_map[rtd->cpu_dai->id].dai_id;
+ pcm_data = &pdata->pcm[dai][substream->stream];
mutex_lock(&pcm_data->mutex);
ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
@@ -685,15 +723,6 @@ static struct snd_pcm_ops hsw_pcm_ops = {
.page = snd_pcm_sgbuf_ops_page,
};
-/* static mappings between PCMs and modules - may be dynamic in future */
-static struct hsw_pcm_module_map mod_map[] = {
- {HSW_PCM_DAI_ID_SYSTEM, SST_HSW_MODULE_PCM_SYSTEM},
- {HSW_PCM_DAI_ID_OFFLOAD0, SST_HSW_MODULE_PCM},
- {HSW_PCM_DAI_ID_OFFLOAD1, SST_HSW_MODULE_PCM},
- {HSW_PCM_DAI_ID_LOOPBACK, SST_HSW_MODULE_PCM_REFERENCE},
- {HSW_PCM_DAI_ID_CAPTURE, SST_HSW_MODULE_PCM_CAPTURE},
-};
-
static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
{
struct sst_hsw *hsw = pdata->hsw;
@@ -701,7 +730,7 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
int i;
for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
- pcm_data = &pdata->pcm[i];
+ pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
/* create new runtime module, use same offset if recreated */
pcm_data->runtime = sst_hsw_runtime_module_create(hsw,
@@ -716,7 +745,7 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
err:
for (--i; i >= 0; i--) {
- pcm_data = &pdata->pcm[i];
+ pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
sst_hsw_runtime_module_free(pcm_data->runtime);
}
@@ -729,17 +758,12 @@ static void hsw_pcm_free_modules(struct hsw_priv_data *pdata)
int i;
for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
- pcm_data = &pdata->pcm[i];
+ pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
sst_hsw_runtime_module_free(pcm_data->runtime);
}
}
-static void hsw_pcm_free(struct snd_pcm *pcm)
-{
- snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_pcm *pcm = rtd->pcm;
@@ -762,7 +786,10 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
return ret;
}
}
- priv_data->pcm[rtd->cpu_dai->id].hsw_pcm = pcm;
+ if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
+ priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_PLAYBACK].hsw_pcm = pcm;
+ if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream)
+ priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_CAPTURE].hsw_pcm = pcm;
return ret;
}
@@ -871,10 +898,9 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
/* allocate DSP buffer page tables */
for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
- mutex_init(&priv_data->pcm[i].mutex);
-
/* playback */
if (hsw_dais[i].playback.channels_min) {
+ mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_PLAYBACK].mutex);
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
PAGE_SIZE, &priv_data->dmab[i][0]);
if (ret < 0)
@@ -883,6 +909,7 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
/* capture */
if (hsw_dais[i].capture.channels_min) {
+ mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_CAPTURE].mutex);
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
PAGE_SIZE, &priv_data->dmab[i][1]);
if (ret < 0)
@@ -936,7 +963,6 @@ static struct snd_soc_platform_driver hsw_soc_platform = {
.remove = hsw_pcm_remove,
.ops = &hsw_pcm_ops,
.pcm_new = hsw_pcm_new,
- .pcm_free = hsw_pcm_free,
};
static const struct snd_soc_component_driver hsw_dai_component = {
@@ -1010,12 +1036,12 @@ static int hsw_pcm_runtime_suspend(struct device *dev)
struct hsw_priv_data *pdata = dev_get_drvdata(dev);
struct sst_hsw *hsw = pdata->hsw;
- if (pdata->pm_state == HSW_PM_STATE_D3)
+ if (pdata->pm_state >= HSW_PM_STATE_RTD3)
return 0;
sst_hsw_dsp_runtime_suspend(hsw);
sst_hsw_dsp_runtime_sleep(hsw);
- pdata->pm_state = HSW_PM_STATE_D3;
+ pdata->pm_state = HSW_PM_STATE_RTD3;
return 0;
}
@@ -1026,7 +1052,7 @@ static int hsw_pcm_runtime_resume(struct device *dev)
struct sst_hsw *hsw = pdata->hsw;
int ret;
- if (pdata->pm_state == HSW_PM_STATE_D0)
+ if (pdata->pm_state != HSW_PM_STATE_RTD3)
return 0;
ret = sst_hsw_dsp_load(hsw);
@@ -1066,7 +1092,7 @@ static void hsw_pcm_complete(struct device *dev)
struct hsw_pcm_data *pcm_data;
int i, err;
- if (pdata->pm_state == HSW_PM_STATE_D0)
+ if (pdata->pm_state != HSW_PM_STATE_D3)
return;
err = sst_hsw_dsp_load(hsw);
@@ -1081,8 +1107,8 @@ static void hsw_pcm_complete(struct device *dev)
return;
}
- for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) {
- pcm_data = &pdata->pcm[i];
+ for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+ pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
if (!pcm_data->substream)
continue;
@@ -1114,41 +1140,42 @@ static int hsw_pcm_prepare(struct device *dev)
if (pdata->pm_state == HSW_PM_STATE_D3)
return 0;
- /* suspend all active streams */
- for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) {
- pcm_data = &pdata->pcm[i];
+ else if (pdata->pm_state == HSW_PM_STATE_D0) {
+ /* suspend all active streams */
+ for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+ pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
+
+ if (!pcm_data->substream)
+ continue;
+ dev_dbg(dev, "suspending pcm %d\n", i);
+ snd_pcm_suspend_all(pcm_data->hsw_pcm);
+
+ /* We need to wait until the DSP FW stops the streams */
+ msleep(2);
+ }
- if (!pcm_data->substream)
- continue;
- dev_dbg(dev, "suspending pcm %d\n", i);
- snd_pcm_suspend_all(pcm_data->hsw_pcm);
+ /* preserve persistent memory */
+ for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+ pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
+
+ if (!pcm_data->substream)
+ continue;
- /* We need to wait until the DSP FW stops the streams */
- msleep(2);
+ dev_dbg(dev, "saving context pcm %d\n", i);
+ err = sst_module_runtime_save(pcm_data->runtime,
+ &pcm_data->context);
+ if (err < 0)
+ dev_err(dev, "failed to save context for PCM %d\n", i);
+ }
+ /* enter D3 state and stall */
+ sst_hsw_dsp_runtime_suspend(hsw);
+ /* put the DSP to sleep */
+ sst_hsw_dsp_runtime_sleep(hsw);
}
snd_soc_suspend(pdata->soc_card->dev);
snd_soc_poweroff(pdata->soc_card->dev);
- /* enter D3 state and stall */
- sst_hsw_dsp_runtime_suspend(hsw);
-
- /* preserve persistent memory */
- for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) {
- pcm_data = &pdata->pcm[i];
-
- if (!pcm_data->substream)
- continue;
-
- dev_dbg(dev, "saving context pcm %d\n", i);
- err = sst_module_runtime_save(pcm_data->runtime,
- &pcm_data->context);
- if (err < 0)
- dev_err(dev, "failed to save context for PCM %d\n", i);
- }
-
- /* put the DSP to sleep */
- sst_hsw_dsp_runtime_sleep(hsw);
pdata->pm_state = HSW_PM_STATE_D3;
return 0;
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c
index a1a8d9d91539..7523cbef8780 100644
--- a/sound/soc/intel/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/sst-mfld-platform-pcm.c
@@ -643,12 +643,6 @@ static struct snd_pcm_ops sst_platform_ops = {
.pointer = sst_platform_pcm_pointer,
};
-static void sst_pcm_free(struct snd_pcm *pcm)
-{
- dev_dbg(pcm->dev, "sst_pcm_free called\n");
- snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *dai = rtd->cpu_dai;
@@ -679,7 +673,6 @@ static struct snd_soc_platform_driver sst_soc_platform_drv = {
.ops = &sst_platform_ops,
.compr_ops = &sst_platform_compr_ops,
.pcm_new = sst_pcm_new,
- .pcm_free = sst_pcm_free,
};
static const struct snd_soc_component_driver sst_component = {
diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/sst/sst_acpi.c
index b3360139c41a..378ef3c3042c 100644
--- a/sound/soc/intel/sst/sst_acpi.c
+++ b/sound/soc/intel/sst/sst_acpi.c
@@ -245,7 +245,7 @@ static struct sst_machines *sst_acpi_find_machine(
return NULL;
}
-int sst_acpi_probe(struct platform_device *pdev)
+static int sst_acpi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int ret = 0;
@@ -332,7 +332,7 @@ do_sst_cleanup:
* This function is called by OS when a device is unloaded
* This frees the interrupt etc
*/
-int sst_acpi_remove(struct platform_device *pdev)
+static int sst_acpi_remove(struct platform_device *pdev)
{
struct intel_sst_drv *ctx;
@@ -352,6 +352,8 @@ static struct sst_machines sst_acpi_bytcr[] = {
static struct sst_machines sst_acpi_chv[] = {
{"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "intel/fw_sst_22a8.bin",
&chv_platform_data },
+ {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin",
+ &chv_platform_data },
{},
};
@@ -366,7 +368,6 @@ MODULE_DEVICE_TABLE(acpi, sst_acpi_ids);
static struct platform_driver sst_acpi_driver = {
.driver = {
.name = "intel_sst_acpi",
- .owner = THIS_MODULE,
.acpi_match_table = ACPI_PTR(sst_acpi_ids),
.pm = &intel_sst_pm,
},
diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c
index b580f96e25e5..7888cd707853 100644
--- a/sound/soc/intel/sst/sst_loader.c
+++ b/sound/soc/intel/sst/sst_loader.c
@@ -324,8 +324,7 @@ void sst_firmware_load_cb(const struct firmware *fw, void *context)
if (ctx->sst_state != SST_RESET ||
ctx->fw_in_mem != NULL) {
- if (fw != NULL)
- release_firmware(fw);
+ release_firmware(fw);
mutex_unlock(&ctx->sst_lock);
return;
}