diff options
-rw-r--r-- | Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5514.txt | 15 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/sound/mt8173-rt5650.txt | 15 | ||||
-rw-r--r-- | sound/soc/codecs/max98926.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/nau8825.c | 169 | ||||
-rw-r--r-- | sound/soc/codecs/nau8825.h | 16 | ||||
-rw-r--r-- | sound/soc/mediatek/Kconfig | 22 | ||||
-rw-r--r-- | sound/soc/mediatek/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/mediatek/mt8173-rt5650-rt5514.c | 258 | ||||
-rw-r--r-- | sound/soc/mediatek/mt8173-rt5650-rt5676.c | 18 | ||||
-rw-r--r-- | sound/soc/mediatek/mt8173-rt5650.c | 236 | ||||
-rw-r--r-- | sound/soc/mediatek/mtk-afe-common.h | 1 | ||||
-rw-r--r-- | sound/soc/mediatek/mtk-afe-pcm.c | 47 | ||||
-rw-r--r-- | sound/soc/mxs/mxs-saif.c | 2 | ||||
-rw-r--r-- | sound/soc/omap/omap-hdmi-audio.c | 1 |
14 files changed, 744 insertions, 62 deletions
diff --git a/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5514.txt b/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5514.txt new file mode 100644 index 000000000000..e8b3c80c6fff --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5514.txt @@ -0,0 +1,15 @@ +MT8173 with RT5650 RT5514 CODECS + +Required properties: +- compatible : "mediatek,mt8173-rt5650-rt5514" +- mediatek,audio-codec: the phandles of rt5650 and rt5514 codecs +- mediatek,platform: the phandle of MT8173 ASoC platform + +Example: + + sound { + compatible = "mediatek,mt8173-rt5650-rt5514"; + mediatek,audio-codec = <&rt5650 &rt5514>; + mediatek,platform = <&afe>; + }; + diff --git a/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt b/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt new file mode 100644 index 000000000000..fe5a5ef1714d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt @@ -0,0 +1,15 @@ +MT8173 with RT5650 CODECS + +Required properties: +- compatible : "mediatek,mt8173-rt5650" +- mediatek,audio-codec: the phandles of rt5650 codecs +- mediatek,platform: the phandle of MT8173 ASoC platform + +Example: + + sound { + compatible = "mediatek,mt8173-rt5650"; + mediatek,audio-codec = <&rt5650>; + mediatek,platform = <&afe>; + }; + diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index 5245e107de30..8d14adae5cc5 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -40,7 +40,7 @@ static const char *const max98926_hpf_cutoff_txt[] = { "200Hz", "400Hz", "800Hz", }; -static struct reg_default max98926_reg[] = { +static const struct reg_default max98926_reg[] = { { 0x0B, 0x00 }, /* IRQ Enable0 */ { 0x0C, 0x00 }, /* IRQ Enable1 */ { 0x0D, 0x00 }, /* IRQ Enable2 */ @@ -506,7 +506,7 @@ static struct snd_soc_codec_driver soc_codec_dev_max98926 = { .num_dapm_widgets = ARRAY_SIZE(max98926_dapm_widgets), }; -static struct regmap_config max98926_regmap = { +static const struct regmap_config max98926_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = MAX98926_VERSION, diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index c1b87c5800b1..1c8729984c2b 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -84,6 +84,7 @@ static const struct nau8825_fll_attr fll_pre_scalar[] = { static const struct reg_default nau8825_reg_defaults[] = { { NAU8825_REG_ENA_CTRL, 0x00ff }, + { NAU8825_REG_IIC_ADDR_SET, 0x0 }, { NAU8825_REG_CLK_DIVIDER, 0x0050 }, { NAU8825_REG_FLL1, 0x0 }, { NAU8825_REG_FLL2, 0x3126 }, @@ -158,8 +159,7 @@ static const struct reg_default nau8825_reg_defaults[] = { static bool nau8825_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { - case NAU8825_REG_ENA_CTRL: - case NAU8825_REG_CLK_DIVIDER ... NAU8825_REG_FLL_VCO_RSV: + case NAU8825_REG_ENA_CTRL ... NAU8825_REG_FLL_VCO_RSV: case NAU8825_REG_HSD_CTRL ... NAU8825_REG_JACK_DET_CTRL: case NAU8825_REG_INTERRUPT_MASK ... NAU8825_REG_KEYDET_CTRL: case NAU8825_REG_VDET_THRESHOLD_1 ... NAU8825_REG_DACR_CTRL: @@ -184,8 +184,7 @@ static bool nau8825_readable_reg(struct device *dev, unsigned int reg) static bool nau8825_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { - case NAU8825_REG_RESET ... NAU8825_REG_ENA_CTRL: - case NAU8825_REG_CLK_DIVIDER ... NAU8825_REG_FLL_VCO_RSV: + case NAU8825_REG_RESET ... NAU8825_REG_FLL_VCO_RSV: case NAU8825_REG_HSD_CTRL ... NAU8825_REG_JACK_DET_CTRL: case NAU8825_REG_INTERRUPT_MASK: case NAU8825_REG_INT_CLR_KEY_STATUS ... NAU8825_REG_KEYDET_CTRL: @@ -227,10 +226,42 @@ static bool nau8825_volatile_reg(struct device *dev, unsigned int reg) static int nau8825_pump_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); + switch (event) { case SND_SOC_DAPM_POST_PMU: /* Prevent startup click by letting charge pump to ramp up */ msleep(10); + regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP, + NAU8825_JAMNODCLOW, NAU8825_JAMNODCLOW); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP, + NAU8825_JAMNODCLOW, 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int nau8825_output_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Disables the TESTDAC to let DAC signal pass through. */ + regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ, + NAU8825_BIAS_TESTDAC_EN, 0); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ, + NAU8825_BIAS_TESTDAC_EN, NAU8825_BIAS_TESTDAC_EN); break; default: return -EINVAL; @@ -316,10 +347,10 @@ static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = { SND_SOC_DAPM_ADC("SAR", NULL, NAU8825_REG_SAR_CTRL, NAU8825_SAR_ADC_EN_SFT, 0), - SND_SOC_DAPM_DAC("ADACL", NULL, NAU8825_REG_RDAC, 12, 0), - SND_SOC_DAPM_DAC("ADACR", NULL, NAU8825_REG_RDAC, 13, 0), - SND_SOC_DAPM_SUPPLY("ADACL Clock", NAU8825_REG_RDAC, 8, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADACR Clock", NAU8825_REG_RDAC, 9, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("ADACL", 2, NAU8825_REG_RDAC, 12, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("ADACR", 2, NAU8825_REG_RDAC, 13, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("ADACL Clock", 3, NAU8825_REG_RDAC, 8, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("ADACR Clock", 3, NAU8825_REG_RDAC, 9, 0, NULL, 0), SND_SOC_DAPM_DAC("DDACR", NULL, NAU8825_REG_ENA_CTRL, NAU8825_ENABLE_DACR_SFT, 0), @@ -330,29 +361,48 @@ static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = { SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &nau8825_dacl_mux), SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &nau8825_dacr_mux), - SND_SOC_DAPM_PGA("HP amp L", NAU8825_REG_CLASSG_CTRL, 1, 0, NULL, 0), - SND_SOC_DAPM_PGA("HP amp R", NAU8825_REG_CLASSG_CTRL, 2, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("HP amp power", NAU8825_REG_CLASSG_CTRL, 0, 0, NULL, - 0), + SND_SOC_DAPM_PGA_S("HP amp L", 0, + NAU8825_REG_CLASSG_CTRL, 1, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("HP amp R", 0, + NAU8825_REG_CLASSG_CTRL, 2, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("Charge Pump", NAU8825_REG_CHARGE_PUMP, 5, 0, - nau8825_pump_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("Charge Pump", 1, NAU8825_REG_CHARGE_PUMP, 5, 0, + nau8825_pump_event, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_PGA("Output Driver R Stage 1", + SND_SOC_DAPM_PGA_S("Output Driver R Stage 1", 4, NAU8825_REG_POWER_UP_CONTROL, 5, 0, NULL, 0), - SND_SOC_DAPM_PGA("Output Driver L Stage 1", + SND_SOC_DAPM_PGA_S("Output Driver L Stage 1", 4, NAU8825_REG_POWER_UP_CONTROL, 4, 0, NULL, 0), - SND_SOC_DAPM_PGA("Output Driver R Stage 2", + SND_SOC_DAPM_PGA_S("Output Driver R Stage 2", 5, NAU8825_REG_POWER_UP_CONTROL, 3, 0, NULL, 0), - SND_SOC_DAPM_PGA("Output Driver L Stage 2", + SND_SOC_DAPM_PGA_S("Output Driver L Stage 2", 5, NAU8825_REG_POWER_UP_CONTROL, 2, 0, NULL, 0), - SND_SOC_DAPM_PGA_S("Output Driver R Stage 3", 1, + SND_SOC_DAPM_PGA_S("Output Driver R Stage 3", 6, NAU8825_REG_POWER_UP_CONTROL, 1, 0, NULL, 0), - SND_SOC_DAPM_PGA_S("Output Driver L Stage 3", 1, + SND_SOC_DAPM_PGA_S("Output Driver L Stage 3", 6, NAU8825_REG_POWER_UP_CONTROL, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA_S("Output DACL", 2, NAU8825_REG_CHARGE_PUMP, 8, 1, NULL, 0), - SND_SOC_DAPM_PGA_S("Output DACR", 2, NAU8825_REG_CHARGE_PUMP, 9, 1, NULL, 0), + SND_SOC_DAPM_PGA_S("Output DACL", 7, + NAU8825_REG_CHARGE_PUMP, 8, 1, nau8825_output_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_S("Output DACR", 7, + NAU8825_REG_CHARGE_PUMP, 9, 1, nau8825_output_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* HPOL/R are ungrounded by disabling 16 Ohm pull-downs on playback */ + SND_SOC_DAPM_PGA_S("HPOL Pulldown", 8, + NAU8825_REG_HSD_CTRL, 0, 1, NULL, 0), + SND_SOC_DAPM_PGA_S("HPOR Pulldown", 8, + NAU8825_REG_HSD_CTRL, 1, 1, NULL, 0), + + /* High current HPOL/R boost driver */ + SND_SOC_DAPM_PGA_S("HP Boost Driver", 9, + NAU8825_REG_BOOST, 9, 1, NULL, 0), + + /* Class G operation control*/ + SND_SOC_DAPM_PGA_S("Class G", 10, + NAU8825_REG_CLASSG_CTRL, 0, 0, NULL, 0), SND_SOC_DAPM_OUTPUT("HPOL"), SND_SOC_DAPM_OUTPUT("HPOR"), @@ -375,24 +425,27 @@ static const struct snd_soc_dapm_route nau8825_dapm_routes[] = { {"DACR Mux", "DACR", "DDACR"}, {"HP amp L", NULL, "DACL Mux"}, {"HP amp R", NULL, "DACR Mux"}, - {"HP amp L", NULL, "HP amp power"}, - {"HP amp R", NULL, "HP amp power"}, - {"ADACL", NULL, "HP amp L"}, - {"ADACR", NULL, "HP amp R"}, - {"ADACL", NULL, "ADACL Clock"}, - {"ADACR", NULL, "ADACR Clock"}, - {"Output Driver L Stage 1", NULL, "ADACL"}, - {"Output Driver R Stage 1", NULL, "ADACR"}, + {"Charge Pump", NULL, "HP amp L"}, + {"Charge Pump", NULL, "HP amp R"}, + {"ADACL", NULL, "Charge Pump"}, + {"ADACR", NULL, "Charge Pump"}, + {"ADACL Clock", NULL, "ADACL"}, + {"ADACR Clock", NULL, "ADACR"}, + {"Output Driver L Stage 1", NULL, "ADACL Clock"}, + {"Output Driver R Stage 1", NULL, "ADACR Clock"}, {"Output Driver L Stage 2", NULL, "Output Driver L Stage 1"}, {"Output Driver R Stage 2", NULL, "Output Driver R Stage 1"}, {"Output Driver L Stage 3", NULL, "Output Driver L Stage 2"}, {"Output Driver R Stage 3", NULL, "Output Driver R Stage 2"}, {"Output DACL", NULL, "Output Driver L Stage 3"}, {"Output DACR", NULL, "Output Driver R Stage 3"}, - {"HPOL", NULL, "Output DACL"}, - {"HPOR", NULL, "Output DACR"}, - {"HPOL", NULL, "Charge Pump"}, - {"HPOR", NULL, "Charge Pump"}, + {"HPOL Pulldown", NULL, "Output DACL"}, + {"HPOR Pulldown", NULL, "Output DACR"}, + {"HP Boost Driver", NULL, "HPOL Pulldown"}, + {"HP Boost Driver", NULL, "HPOR Pulldown"}, + {"Class G", NULL, "HP Boost Driver"}, + {"HPOL", NULL, "Class G"}, + {"HPOR", NULL, "Class G"}, }; static int nau8825_hw_params(struct snd_pcm_substream *substream, @@ -659,11 +712,10 @@ static int nau8825_jack_insert(struct nau8825 *nau8825) break; } - if (type & SND_JACK_HEADPHONE) { - /* Unground HPL/R */ - regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, 0x3, 0); - } - + /* Leaving HPOL/R grounded after jack insert by default. They will be + * ungrounded as part of the widget power up sequence at the beginning + * of playback to reduce pop. + */ return type; } @@ -768,6 +820,8 @@ static void nau8825_init_regs(struct nau8825 *nau8825) { struct regmap *regmap = nau8825->regmap; + /* Latch IIC LSB value */ + regmap_write(regmap, NAU8825_REG_IIC_ADDR_SET, 0x0001); /* Enable Bias/Vmid */ regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ, NAU8825_BIAS_VMID, NAU8825_BIAS_VMID); @@ -780,10 +834,10 @@ static void nau8825_init_regs(struct nau8825 *nau8825) nau8825->vref_impedance << NAU8825_BIAS_VMID_SEL_SFT); /* Disable Boost Driver, Automatic Short circuit protection enable */ regmap_update_bits(regmap, NAU8825_REG_BOOST, - NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_G_DIS | - NAU8825_SHORT_SHUTDOWN_EN, - NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_G_DIS | - NAU8825_SHORT_SHUTDOWN_EN); + NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_DIS | + NAU8825_HP_BOOST_G_DIS | NAU8825_SHORT_SHUTDOWN_EN, + NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_DIS | + NAU8825_HP_BOOST_G_DIS | NAU8825_SHORT_SHUTDOWN_EN); regmap_update_bits(regmap, NAU8825_REG_GPIO12_CTRL, NAU8825_JKDET_OUTPUT_EN, @@ -822,6 +876,35 @@ static void nau8825_init_regs(struct nau8825 *nau8825) NAU8825_ADC_SYNC_DOWN_MASK, NAU8825_ADC_SYNC_DOWN_128); regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1, NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_128); + /* Disable DACR/L power */ + regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP, + NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, + NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL); + /* Enable TESTDAC. This sets the analog DAC inputs to a '0' input + * signal to avoid any glitches due to power up transients in both + * the analog and digital DAC circuit. + */ + regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ, + NAU8825_BIAS_TESTDAC_EN, NAU8825_BIAS_TESTDAC_EN); + /* CICCLP off */ + regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1, + NAU8825_DAC_CLIP_OFF, NAU8825_DAC_CLIP_OFF); + + /* Class AB bias current to 2x, DAC Capacitor enable MSB/LSB */ + regmap_update_bits(regmap, NAU8825_REG_ANALOG_CONTROL_2, + NAU8825_HP_NON_CLASSG_CURRENT_2xADJ | + NAU8825_DAC_CAPACITOR_MSB | NAU8825_DAC_CAPACITOR_LSB, + NAU8825_HP_NON_CLASSG_CURRENT_2xADJ | + NAU8825_DAC_CAPACITOR_MSB | NAU8825_DAC_CAPACITOR_LSB); + /* Class G timer 64ms */ + regmap_update_bits(regmap, NAU8825_REG_CLASSG_CTRL, + NAU8825_CLASSG_TIMER_MASK, + 0x20 << NAU8825_CLASSG_TIMER_SFT); + /* DAC clock delay 2ns, VREF */ + regmap_update_bits(regmap, NAU8825_REG_RDAC, + NAU8825_RDAC_CLK_DELAY_MASK | NAU8825_RDAC_VREF_MASK, + (0x2 << NAU8825_RDAC_CLK_DELAY_SFT) | + (0x3 << NAU8825_RDAC_VREF_SFT)); } static const struct regmap_config nau8825_regmap_config = { diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index dff8edb83bfd..8ceb5f385478 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -14,6 +14,7 @@ #define NAU8825_REG_RESET 0x00 #define NAU8825_REG_ENA_CTRL 0x01 +#define NAU8825_REG_IIC_ADDR_SET 0x02 #define NAU8825_REG_CLK_DIVIDER 0x03 #define NAU8825_REG_FLL1 0x04 #define NAU8825_REG_FLL2 0x05 @@ -129,7 +130,7 @@ /* HSD_CTRL (0xc) */ #define NAU8825_HSD_AUTO_MODE (1 << 6) -/* 0 - short to GND, 1 - open */ +/* 0 - open, 1 - short to GND */ #define NAU8825_SPKR_DWN1R (1 << 1) #define NAU8825_SPKR_DWN1L (1 << 0) @@ -251,12 +252,18 @@ /* DACR_CTRL (0x34) */ #define NAU8825_DACR_CH_SEL_SFT 9 +/* CLASSG_CTRL (0x50) */ +#define NAU8825_CLASSG_TIMER_SFT 8 +#define NAU8825_CLASSG_TIMER_MASK (0x3f << NAU8825_CLASSG_TIMER_SFT) +#define NAU8825_CLASSG_EN (1 << 0) + /* I2C_DEVICE_ID (0x58) */ #define NAU8825_GPIO2JD1 (1 << 7) #define NAU8825_SOFTWARE_ID_MASK 0x3 #define NAU8825_SOFTWARE_ID_NAU8825 0x0 /* BIAS_ADJ (0x66) */ +#define NAU8825_BIAS_TESTDAC_EN (0x3 << 8) #define NAU8825_BIAS_VMID (1 << 6) #define NAU8825_BIAS_VMID_SEL_SFT 4 #define NAU8825_BIAS_VMID_SEL_MASK (3 << NAU8825_BIAS_VMID_SEL_SFT) @@ -274,6 +281,12 @@ #define NAU8825_ADC_VREFSEL_VMID_PLUS_1DB (3 << 8) #define NAU8825_POWERUP_ADCL (1 << 6) +/* RDAC (0x73) */ +#define NAU8825_RDAC_CLK_DELAY_SFT 4 +#define NAU8825_RDAC_CLK_DELAY_MASK (0x7 << NAU8825_RDAC_CLK_DELAY_SFT) +#define NAU8825_RDAC_VREF_SFT 2 +#define NAU8825_RDAC_VREF_MASK (0x3 << NAU8825_RDAC_VREF_SFT) + /* MIC_BIAS (0x74) */ #define NAU8825_MICBIAS_JKSLV (1 << 14) #define NAU8825_MICBIAS_JKR2 (1 << 12) @@ -284,6 +297,7 @@ /* BOOST (0x76) */ #define NAU8825_PRECHARGE_DIS (1 << 13) #define NAU8825_GLOBAL_BIAS_EN (1 << 12) +#define NAU8825_HP_BOOST_DIS (1 << 9) #define NAU8825_HP_BOOST_G_DIS (1 << 8) #define NAU8825_SHORT_SHUTDOWN_EN (1 << 6) diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 976967675387..f7e789e97fbc 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -17,6 +17,27 @@ config SND_SOC_MT8173_MAX98090 Select Y if you have such device. If unsure select "N". +config SND_SOC_MT8173_RT5650 + tristate "ASoC Audio driver for MT8173 with RT5650 codec" + depends on SND_SOC_MEDIATEK && I2C + select SND_SOC_RT5645 + help + This adds ASoC driver for Mediatek MT8173 boards + with the RT5650 audio codec. + Select Y if you have such device. + If unsure select "N". + +config SND_SOC_MT8173_RT5650_RT5514 + tristate "ASoC Audio driver for MT8173 with RT5650 RT5514 codecs" + depends on SND_SOC_MEDIATEK && I2C + select SND_SOC_RT5645 + select SND_SOC_RT5514 + help + This adds ASoC driver for Mediatek MT8173 boards + with the RT5650 and RT5514 codecs. + Select Y if you have such device. + If unsure select "N". + config SND_SOC_MT8173_RT5650_RT5676 tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs" depends on SND_SOC_MEDIATEK && I2C @@ -27,4 +48,3 @@ config SND_SOC_MT8173_RT5650_RT5676 with the RT5650 and RT5676 codecs. Select Y if you have such device. If unsure select "N". - diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index 75effbec438d..d486860c0a88 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile @@ -2,4 +2,6 @@ obj-$(CONFIG_SND_SOC_MEDIATEK) += mtk-afe-pcm.o # Machine support obj-$(CONFIG_SND_SOC_MT8173_MAX98090) += mt8173-max98090.o +obj-$(CONFIG_SND_SOC_MT8173_RT5650) += mt8173-rt5650.o +obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5514) += mt8173-rt5650-rt5514.o obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5676) += mt8173-rt5650-rt5676.o diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173-rt5650-rt5514.c new file mode 100644 index 000000000000..58e083642dea --- /dev/null +++ b/sound/soc/mediatek/mt8173-rt5650-rt5514.c @@ -0,0 +1,258 @@ +/* + * mt8173-rt5650-rt5514.c -- MT8173 machine driver with RT5650/5514 codecs + * + * Copyright (c) 2016 MediaTek Inc. + * Author: Koro Chen <koro.chen@mediatek.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 and + * only version 2 as published by the Free Software Foundation. + * + * 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/gpio.h> +#include <linux/of_gpio.h> +#include <sound/soc.h> +#include <sound/jack.h> +#include "../codecs/rt5645.h" + +#define MCLK_FOR_CODECS 12288000 + +static const struct snd_soc_dapm_widget mt8173_rt5650_rt5514_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_dapm_route mt8173_rt5650_rt5514_routes[] = { + {"Speaker", NULL, "SPOL"}, + {"Speaker", NULL, "SPOR"}, + {"Sub DMIC1L", NULL, "Int Mic"}, + {"Sub DMIC1R", NULL, "Int Mic"}, + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + {"Headset Mic", NULL, "micbias1"}, + {"Headset Mic", NULL, "micbias2"}, + {"IN1P", NULL, "Headset Mic"}, + {"IN1N", NULL, "Headset Mic"}, +}; + +static const struct snd_kcontrol_new mt8173_rt5650_rt5514_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static int mt8173_rt5650_rt5514_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int i, ret; + + for (i = 0; i < rtd->num_codecs; i++) { + struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + + /* pll from mclk 12.288M */ + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS, + params_rate(params) * 512); + if (ret) + return ret; + + /* sysclk from pll */ + ret = snd_soc_dai_set_sysclk(codec_dai, 1, + params_rate(params) * 512, + SND_SOC_CLOCK_IN); + if (ret) + return ret; + } + return 0; +} + +static struct snd_soc_ops mt8173_rt5650_rt5514_ops = { + .hw_params = mt8173_rt5650_rt5514_hw_params, +}; + +static struct snd_soc_jack mt8173_rt5650_rt5514_jack; + +static int mt8173_rt5650_rt5514_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_card *card = runtime->card; + struct snd_soc_codec *codec = runtime->codec_dais[0]->codec; + int ret; + + rt5645_sel_asrc_clk_src(codec, + RT5645_DA_STEREO_FILTER | + RT5645_AD_STEREO_FILTER, + RT5645_CLK_SEL_I2S1_ASRC); + + /* enable jack detection */ + ret = snd_soc_card_jack_new(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &mt8173_rt5650_rt5514_jack, NULL, 0); + if (ret) { + dev_err(card->dev, "Can't new Headset Jack %d\n", ret); + return ret; + } + + return rt5645_set_jack_detect(codec, + &mt8173_rt5650_rt5514_jack, + &mt8173_rt5650_rt5514_jack, + &mt8173_rt5650_rt5514_jack); +} + +static struct snd_soc_dai_link_component mt8173_rt5650_rt5514_codecs[] = { + { + .dai_name = "rt5645-aif1", + }, + { + .dai_name = "rt5514-aif1", + }, +}; + +enum { + DAI_LINK_PLAYBACK, + DAI_LINK_CAPTURE, + DAI_LINK_CODEC_I2S, +}; + +/* Digital audio interface glue - connects codec <---> CPU */ +static struct snd_soc_dai_link mt8173_rt5650_rt5514_dais[] = { + /* Front End DAI links */ + [DAI_LINK_PLAYBACK] = { + .name = "rt5650_rt5514 Playback", + .stream_name = "rt5650_rt5514 Playback", + .cpu_dai_name = "DL1", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_playback = 1, + }, + [DAI_LINK_CAPTURE] = { + .name = "rt5650_rt5514 Capture", + .stream_name = "rt5650_rt5514 Capture", + .cpu_dai_name = "VUL", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_capture = 1, + }, + /* Back End DAI links */ + [DAI_LINK_CODEC_I2S] = { + .name = "Codec", + .cpu_dai_name = "I2S", + .no_pcm = 1, + .codecs = mt8173_rt5650_rt5514_codecs, + .num_codecs = 2, + .init = mt8173_rt5650_rt5514_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ops = &mt8173_rt5650_rt5514_ops, + .ignore_pmdown_time = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, +}; + +static struct snd_soc_codec_conf mt8173_rt5650_rt5514_codec_conf[] = { + { + .name_prefix = "Sub", + }, +}; + +static struct snd_soc_card mt8173_rt5650_rt5514_card = { + .name = "mtk-rt5650-rt5514", + .owner = THIS_MODULE, + .dai_link = mt8173_rt5650_rt5514_dais, + .num_links = ARRAY_SIZE(mt8173_rt5650_rt5514_dais), + .codec_conf = mt8173_rt5650_rt5514_codec_conf, + .num_configs = ARRAY_SIZE(mt8173_rt5650_rt5514_codec_conf), + .controls = mt8173_rt5650_rt5514_controls, + .num_controls = ARRAY_SIZE(mt8173_rt5650_rt5514_controls), + .dapm_widgets = mt8173_rt5650_rt5514_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8173_rt5650_rt5514_widgets), + .dapm_routes = mt8173_rt5650_rt5514_routes, + .num_dapm_routes = ARRAY_SIZE(mt8173_rt5650_rt5514_routes), +}; + +static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &mt8173_rt5650_rt5514_card; + struct device_node *platform_node; + int i, ret; + + platform_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,platform", 0); + if (!platform_node) { + dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); + return -EINVAL; + } + + for (i = 0; i < card->num_links; i++) { + if (mt8173_rt5650_rt5514_dais[i].platform_name) + continue; + mt8173_rt5650_rt5514_dais[i].platform_of_node = platform_node; + } + + mt8173_rt5650_rt5514_codecs[0].of_node = + of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0); + if (!mt8173_rt5650_rt5514_codecs[0].of_node) { + dev_err(&pdev->dev, + "Property 'audio-codec' missing or invalid\n"); + return -EINVAL; + } + mt8173_rt5650_rt5514_codecs[1].of_node = + of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1); + if (!mt8173_rt5650_rt5514_codecs[1].of_node) { + dev_err(&pdev->dev, + "Property 'audio-codec' missing or invalid\n"); + return -EINVAL; + } + mt8173_rt5650_rt5514_codec_conf[0].of_node = + mt8173_rt5650_rt5514_codecs[1].of_node; + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) + dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", + __func__, ret); + return ret; +} + +static const struct of_device_id mt8173_rt5650_rt5514_dt_match[] = { + { .compatible = "mediatek,mt8173-rt5650-rt5514", }, + { } +}; +MODULE_DEVICE_TABLE(of, mt8173_rt5650_rt5514_dt_match); + +static struct platform_driver mt8173_rt5650_rt5514_driver = { + .driver = { + .name = "mtk-rt5650-rt5514", + .of_match_table = mt8173_rt5650_rt5514_dt_match, +#ifdef CONFIG_PM + .pm = &snd_soc_pm_ops, +#endif + }, + .probe = mt8173_rt5650_rt5514_dev_probe, +}; + +module_platform_driver(mt8173_rt5650_rt5514_driver); + +/* Module information */ +MODULE_DESCRIPTION("MT8173 RT5650 and RT5514 SoC machine driver"); +MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:mtk-rt5650-rt5514"); + diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173-rt5650-rt5676.c index 50ba538eccb3..5c4c58c69c51 100644 --- a/sound/soc/mediatek/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173-rt5650-rt5676.c @@ -131,10 +131,17 @@ static struct snd_soc_dai_link_component mt8173_rt5650_rt5676_codecs[] = { }, }; +enum { + DAI_LINK_PLAYBACK, + DAI_LINK_CAPTURE, + DAI_LINK_CODEC_I2S, + DAI_LINK_INTERCODEC +}; + /* Digital audio interface glue - connects codec <---> CPU */ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { /* Front End DAI links */ - { + [DAI_LINK_PLAYBACK] = { .name = "rt5650_rt5676 Playback", .stream_name = "rt5650_rt5676 Playback", .cpu_dai_name = "DL1", @@ -144,7 +151,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { .dynamic = 1, .dpcm_playback = 1, }, - { + [DAI_LINK_CAPTURE] = { .name = "rt5650_rt5676 Capture", .stream_name = "rt5650_rt5676 Capture", .cpu_dai_name = "VUL", @@ -156,7 +163,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { }, /* Back End DAI links */ - { + [DAI_LINK_CODEC_I2S] = { .name = "Codec", .cpu_dai_name = "I2S", .no_pcm = 1, @@ -170,7 +177,8 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { .dpcm_playback = 1, .dpcm_capture = 1, }, - { /* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */ + /* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */ + [DAI_LINK_INTERCODEC] = { .name = "rt5650_rt5676 intercodec", .stream_name = "rt5650_rt5676 intercodec", .cpu_dai_name = "snd-soc-dummy-dai", @@ -240,7 +248,7 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) mt8173_rt5650_rt5676_codec_conf[0].of_node = mt8173_rt5650_rt5676_codecs[1].of_node; - mt8173_rt5650_rt5676_dais[3].codec_of_node = + mt8173_rt5650_rt5676_dais[DAI_LINK_INTERCODEC].codec_of_node = mt8173_rt5650_rt5676_codecs[1].of_node; card->dev = &pdev->dev; diff --git a/sound/soc/mediatek/mt8173-rt5650.c b/sound/soc/mediatek/mt8173-rt5650.c new file mode 100644 index 000000000000..bb09bb1b7f1c --- /dev/null +++ b/sound/soc/mediatek/mt8173-rt5650.c @@ -0,0 +1,236 @@ +/* + * mt8173-rt5650.c -- MT8173 machine driver with RT5650 codecs + * + * Copyright (c) 2016 MediaTek Inc. + * Author: Koro Chen <koro.chen@mediatek.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 and + * only version 2 as published by the Free Software Foundation. + * + * 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/gpio.h> +#include <linux/of_gpio.h> +#include <sound/soc.h> +#include <sound/jack.h> +#include "../codecs/rt5645.h" + +#define MCLK_FOR_CODECS 12288000 + +static const struct snd_soc_dapm_widget mt8173_rt5650_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_dapm_route mt8173_rt5650_routes[] = { + {"Speaker", NULL, "SPOL"}, + {"Speaker", NULL, "SPOR"}, + {"DMIC L1", NULL, "Int Mic"}, + {"DMIC R1", NULL, "Int Mic"}, + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + {"Headset Mic", NULL, "micbias1"}, + {"Headset Mic", NULL, "micbias2"}, + {"IN1P", NULL, "Headset Mic"}, + {"IN1N", NULL, "Headset Mic"}, +}; + +static const struct snd_kcontrol_new mt8173_rt5650_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int i, ret; + + for (i = 0; i < rtd->num_codecs; i++) { + struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + + /* pll from mclk 12.288M */ + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS, + params_rate(params) * 512); + if (ret) + return ret; + + /* sysclk from pll */ + ret = snd_soc_dai_set_sysclk(codec_dai, 1, + params_rate(params) * 512, + SND_SOC_CLOCK_IN); + if (ret) + return ret; + } + return 0; +} + +static struct snd_soc_ops mt8173_rt5650_ops = { + .hw_params = mt8173_rt5650_hw_params, +}; + +static struct snd_soc_jack mt8173_rt5650_jack; + +static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_card *card = runtime->card; + struct snd_soc_codec *codec = runtime->codec_dais[0]->codec; + int ret; + + rt5645_sel_asrc_clk_src(codec, + RT5645_DA_STEREO_FILTER | + RT5645_AD_STEREO_FILTER, + RT5645_CLK_SEL_I2S1_ASRC); + /* enable jack detection */ + ret = snd_soc_card_jack_new(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &mt8173_rt5650_jack, NULL, 0); + if (ret) { + dev_err(card->dev, "Can't new Headset Jack %d\n", ret); + return ret; + } + + return rt5645_set_jack_detect(codec, + &mt8173_rt5650_jack, + &mt8173_rt5650_jack, + &mt8173_rt5650_jack); +} + +static struct snd_soc_dai_link_component mt8173_rt5650_codecs[] = { + { + .dai_name = "rt5645-aif1", + }, +}; + +enum { + DAI_LINK_PLAYBACK, + DAI_LINK_CAPTURE, + DAI_LINK_CODEC_I2S, +}; + +/* Digital audio interface glue - connects codec <---> CPU */ +static struct snd_soc_dai_link mt8173_rt5650_dais[] = { + /* Front End DAI links */ + [DAI_LINK_PLAYBACK] = { + .name = "rt5650 Playback", + .stream_name = "rt5650 Playback", + .cpu_dai_name = "DL1", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_playback = 1, + }, + [DAI_LINK_CAPTURE] = { + .name = "rt5650 Capture", + .stream_name = "rt5650 Capture", + .cpu_dai_name = "VUL", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_capture = 1, + }, + /* Back End DAI links */ + [DAI_LINK_CODEC_I2S] = { + .name = "Codec", + .cpu_dai_name = "I2S", + .no_pcm = 1, + .codecs = mt8173_rt5650_codecs, + .num_codecs = 1, + .init = mt8173_rt5650_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ops = &mt8173_rt5650_ops, + .ignore_pmdown_time = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, +}; + +static struct snd_soc_card mt8173_rt5650_card = { + .name = "mtk-rt5650", + .owner = THIS_MODULE, + .dai_link = mt8173_rt5650_dais, + .num_links = ARRAY_SIZE(mt8173_rt5650_dais), + .controls = mt8173_rt5650_controls, + .num_controls = ARRAY_SIZE(mt8173_rt5650_controls), + .dapm_widgets = mt8173_rt5650_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8173_rt5650_widgets), + .dapm_routes = mt8173_rt5650_routes, + .num_dapm_routes = ARRAY_SIZE(mt8173_rt5650_routes), +}; + +static int mt8173_rt5650_dev_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &mt8173_rt5650_card; + struct device_node *platform_node; + int i, ret; + + platform_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,platform", 0); + if (!platform_node) { + dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); + return -EINVAL; + } + + for (i = 0; i < card->num_links; i++) { + if (mt8173_rt5650_dais[i].platform_name) + continue; + mt8173_rt5650_dais[i].platform_of_node = platform_node; + } + + mt8173_rt5650_codecs[0].of_node = + of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0); + if (!mt8173_rt5650_codecs[0].of_node) { + dev_err(&pdev->dev, + "Property 'audio-codec' missing or invalid\n"); + return -EINVAL; + } + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) + dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", + __func__, ret); + return ret; +} + +static const struct of_device_id mt8173_rt5650_dt_match[] = { + { .compatible = "mediatek,mt8173-rt5650", }, + { } +}; +MODULE_DEVICE_TABLE(of, mt8173_rt5650_dt_match); + +static struct platform_driver mt8173_rt5650_driver = { + .driver = { + .name = "mtk-rt5650", + .of_match_table = mt8173_rt5650_dt_match, +#ifdef CONFIG_PM + .pm = &snd_soc_pm_ops, +#endif + }, + .probe = mt8173_rt5650_dev_probe, +}; + +module_platform_driver(mt8173_rt5650_driver); + +/* Module information */ +MODULE_DESCRIPTION("MT8173 RT5650 SoC machine driver"); +MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:mtk-rt5650"); + diff --git a/sound/soc/mediatek/mtk-afe-common.h b/sound/soc/mediatek/mtk-afe-common.h index 9b1af1a70874..f341f623e887 100644 --- a/sound/soc/mediatek/mtk-afe-common.h +++ b/sound/soc/mediatek/mtk-afe-common.h @@ -87,6 +87,7 @@ struct mtk_afe_memif_data { int irq_en_shift; int irq_fs_shift; int irq_clr_shift; + int msb_shift; }; struct mtk_afe_memif { diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c index 08af9f5dc4ab..f1c58a2c12fb 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mtk-afe-pcm.c @@ -21,6 +21,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/dma-mapping.h> #include <linux/pm_runtime.h> #include <sound/soc.h> #include "mtk-afe-common.h" @@ -35,9 +36,11 @@ #define AFE_I2S_CON1 0x0034 #define AFE_I2S_CON2 0x0038 #define AFE_CONN_24BIT 0x006c +#define AFE_MEMIF_MSB 0x00cc #define AFE_CONN1 0x0024 #define AFE_CONN2 0x0028 +#define AFE_CONN3 0x002c #define AFE_CONN7 0x0460 #define AFE_CONN8 0x0464 #define AFE_HDMI_CONN0 0x0390 @@ -61,6 +64,7 @@ #define AFE_HDMI_OUT_CUR 0x0378 #define AFE_HDMI_OUT_END 0x037c +#define AFE_ADDA_TOP_CON0 0x0120 #define AFE_ADDA2_TOP_CON0 0x0600 #define AFE_HDMI_OUT_CON0 0x0370 @@ -257,6 +261,7 @@ static int mtk_afe_set_i2s(struct mtk_afe *afe, unsigned int rate) return -EINVAL; /* from external ADC */ + regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x1); regmap_update_bits(afe->regmap, AFE_ADDA2_TOP_CON0, 0x1, 0x1); /* set input */ @@ -281,20 +286,13 @@ static void mtk_afe_set_i2s_enable(struct mtk_afe *afe, bool enable) regmap_read(afe->regmap, AFE_I2S_CON2, &val); if (!!(val & AFE_I2S_CON2_EN) == enable) - return; /* must skip soft reset */ - - /* I2S soft reset begin */ - regmap_update_bits(afe->regmap, AUDIO_TOP_CON1, 0x4, 0x4); + return; /* input */ regmap_update_bits(afe->regmap, AFE_I2S_CON2, 0x1, enable); /* output */ regmap_update_bits(afe->regmap, AFE_I2S_CON1, 0x1, enable); - - /* I2S soft reset end */ - udelay(1); - regmap_update_bits(afe->regmap, AUDIO_TOP_CON1, 0x4, 0); } static int mtk_afe_dais_enable_clks(struct mtk_afe *afe, @@ -363,6 +361,7 @@ static int mtk_afe_i2s_startup(struct snd_pcm_substream *substream, return 0; mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL); + mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S2_M], NULL); regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0); return 0; @@ -382,6 +381,7 @@ static void mtk_afe_i2s_shutdown(struct snd_pcm_substream *substream, AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M); mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL); + mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S2_M], NULL); } static int mtk_afe_i2s_prepare(struct snd_pcm_substream *substream, @@ -395,6 +395,9 @@ static int mtk_afe_i2s_prepare(struct snd_pcm_substream *substream, mtk_afe_dais_set_clks(afe, afe->clocks[MTK_CLK_I2S1_M], runtime->rate * 256, NULL, 0); + mtk_afe_dais_set_clks(afe, + afe->clocks[MTK_CLK_I2S2_M], runtime->rate * 256, + NULL, 0); /* config I2S */ ret = mtk_afe_set_i2s(afe, substream->runtime->rate); if (ret) @@ -592,6 +595,7 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; + int msb_at_bit33 = 0; int ret; dev_dbg(afe->dev, @@ -603,7 +607,8 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - memif->phys_buf_addr = substream->runtime->dma_addr; + msb_at_bit33 = upper_32_bits(substream->runtime->dma_addr) ? 1 : 0; + memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr); memif->buffer_size = substream->runtime->dma_bytes; /* start */ @@ -614,6 +619,11 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream, memif->data->reg_ofs_base + AFE_BASE_END_OFFSET, memif->phys_buf_addr + memif->buffer_size - 1); + /* set MSB to 33-bit */ + regmap_update_bits(afe->regmap, AFE_MEMIF_MSB, + 1 << memif->data->msb_shift, + msb_at_bit33 << memif->data->msb_shift); + /* set channel */ if (memif->data->mono_shift >= 0) { unsigned int mono = (params_channels(params) == 1) ? 1 : 0; @@ -894,15 +904,19 @@ static const struct snd_kcontrol_new mtk_afe_o04_mix[] = { }; static const struct snd_kcontrol_new mtk_afe_o09_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN3, 0, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN7, 30, 1, 0), }; static const struct snd_kcontrol_new mtk_afe_o10_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN3, 3, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN8, 0, 1, 0), }; static const struct snd_soc_dapm_widget mtk_afe_pcm_widgets[] = { /* inter-connections */ + SND_SOC_DAPM_MIXER("I03", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I04", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I05", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I06", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I17", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -925,12 +939,16 @@ static const struct snd_soc_dapm_route mtk_afe_pcm_routes[] = { {"I2S Playback", NULL, "O04"}, {"VUL", NULL, "O09"}, {"VUL", NULL, "O10"}, + {"I03", NULL, "I2S Capture"}, + {"I04", NULL, "I2S Capture"}, {"I17", NULL, "I2S Capture"}, {"I18", NULL, "I2S Capture"}, { "O03", "I05 Switch", "I05" }, { "O04", "I06 Switch", "I06" }, { "O09", "I17 Switch", "I17" }, + { "O09", "I03 Switch", "I03" }, { "O10", "I18 Switch", "I18" }, + { "O10", "I04 Switch", "I04" }, }; static const struct snd_soc_dapm_route mtk_afe_hdmi_routes[] = { @@ -978,6 +996,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .irq_en_shift = 0, .irq_fs_shift = 4, .irq_clr_shift = 0, + .msb_shift = 0, }, { .name = "DL2", .id = MTK_AFE_MEMIF_DL2, @@ -991,6 +1010,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .irq_en_shift = 2, .irq_fs_shift = 16, .irq_clr_shift = 2, + .msb_shift = 1, }, { .name = "VUL", .id = MTK_AFE_MEMIF_VUL, @@ -1004,6 +1024,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .irq_en_shift = 1, .irq_fs_shift = 8, .irq_clr_shift = 1, + .msb_shift = 6, }, { .name = "DAI", .id = MTK_AFE_MEMIF_DAI, @@ -1017,6 +1038,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .irq_en_shift = 3, .irq_fs_shift = 20, .irq_clr_shift = 3, + .msb_shift = 5, }, { .name = "AWB", .id = MTK_AFE_MEMIF_AWB, @@ -1030,6 +1052,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .irq_en_shift = 14, .irq_fs_shift = 24, .irq_clr_shift = 6, + .msb_shift = 3, }, { .name = "MOD_DAI", .id = MTK_AFE_MEMIF_MOD_DAI, @@ -1043,6 +1066,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .irq_en_shift = 3, .irq_fs_shift = 20, .irq_clr_shift = 3, + .msb_shift = 4, }, { .name = "HDMI", .id = MTK_AFE_MEMIF_HDMI, @@ -1056,6 +1080,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .irq_en_shift = 12, .irq_fs_shift = -1, .irq_clr_shift = 4, + .msb_shift = 8, }, }; @@ -1189,6 +1214,10 @@ static int mtk_afe_pcm_dev_probe(struct platform_device *pdev) struct mtk_afe *afe; struct resource *res; + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33)); + if (ret) + return ret; + afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); if (!afe) return -ENOMEM; diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index a6c7b8d87cd2..13631003cb7c 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -418,7 +418,7 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream, } stat = __raw_readl(saif->base + SAIF_STAT); - if (stat & BM_SAIF_STAT_BUSY) { + if (!saif->mclk_in_use && (stat & BM_SAIF_STAT_BUSY)) { dev_err(cpu_dai->dev, "error: busy\n"); return -EBUSY; } diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c index f83cc2bc0fc4..64425d352962 100644 --- a/sound/soc/omap/omap-hdmi-audio.c +++ b/sound/soc/omap/omap-hdmi-audio.c @@ -345,6 +345,7 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) dai_drv = &omap4_hdmi_dai; break; case OMAPDSS_VER_OMAP5: + case OMAPDSS_VER_DRA7xx: dai_drv = &omap5_hdmi_dai; break; default: |