mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-26 13:44:15 +08:00
Merge remote-tracking branches 'asoc/topic/max98926', 'asoc/topic/mtk', 'asoc/topic/mxs-saif', 'asoc/topic/nau8825' and 'asoc/topic/omap' into asoc-next
This commit is contained in:
commit
88f183484a
@ -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>;
|
||||
};
|
||||
|
15
Documentation/devicetree/bindings/sound/mt8173-rt5650.txt
Normal file
15
Documentation/devicetree/bindings/sound/mt8173-rt5650.txt
Normal file
@ -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>;
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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 = {
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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".
|
||||
|
||||
|
@ -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
|
||||
|
258
sound/soc/mediatek/mt8173-rt5650-rt5514.c
Normal file
258
sound/soc/mediatek/mt8173-rt5650-rt5514.c
Normal file
@ -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");
|
||||
|
@ -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;
|
||||
|
236
sound/soc/mediatek/mt8173-rt5650.c
Normal file
236
sound/soc/mediatek/mt8173-rt5650.c
Normal file
@ -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");
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user