mirror of https://gitee.com/openkylin/linux.git
Merge remote-tracking branches 'asoc/topic/max98504', 'asoc/topic/max9867', 'asoc/topic/max9877', 'asoc/topic/mtk' and 'asoc/topic/nau8825' into asoc-next
This commit is contained in:
commit
c704f4e312
|
@ -0,0 +1,44 @@
|
|||
Maxim MAX98504 class D mono speaker amplifier
|
||||
|
||||
This device supports I2C control interface and an IRQ output signal. It features
|
||||
a PCM and PDM digital audio interface (DAI) and a differential analog input.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "maxim,max98504"
|
||||
- reg : should contain the I2C slave device address
|
||||
- DVDD-supply, DIOVDD-supply, PVDD-supply: power supplies for the device,
|
||||
as covered in ../regulator/regulator.txt
|
||||
- interrupts : should specify the interrupt line the device is connected to,
|
||||
as described in ../interrupt-controller/interrupts.txt
|
||||
|
||||
Optional properties:
|
||||
|
||||
- maxim,brownout-threshold - the PVDD brownout threshold, the value must be
|
||||
from 0, 1...21 range, corresponding to 2.6V, 2.65V...3.65V voltage range
|
||||
- maxim,brownout-attenuation - the brownout attenuation to the speaker gain
|
||||
applied during the "attack hold" and "timed hold" phase, the value must be
|
||||
from 0...6 (dB) range
|
||||
- maxim,brownout-attack-hold-ms - the brownout attack hold phase time in ms,
|
||||
0...255 (VBATBROWN_ATTK_HOLD, register 0x0018)
|
||||
- maxim,brownout-timed-hold-ms - the brownout timed hold phase time in ms,
|
||||
0...255 (VBATBROWN_TIME_HOLD, register 0x0019)
|
||||
- maxim,brownout-release-rate-ms - the brownout release phase step time in ms,
|
||||
0...255 (VBATBROWN_RELEASE, register 0x001A)
|
||||
|
||||
The default value when the above properties are not specified is 0,
|
||||
the maxim,brownout-threshold property must be specified to actually enable
|
||||
the PVDD brownout protection.
|
||||
|
||||
Example:
|
||||
|
||||
max98504@31 {
|
||||
compatible = "maxim,max98504";
|
||||
reg = <0x31>;
|
||||
interrupt-parent = <&gpio_bank_0>;
|
||||
interrupts = <2 0>;
|
||||
|
||||
DVDD-supply = <®ulator>;
|
||||
DIOVDD-supply = <®ulator>;
|
||||
PVDD-supply = <®ulator>;
|
||||
};
|
|
@ -0,0 +1,150 @@
|
|||
Mediatek AFE PCM controller for mt2701
|
||||
|
||||
Required properties:
|
||||
- compatible = "mediatek,mt2701-audio";
|
||||
- reg: register location and size
|
||||
- interrupts: Should contain AFE interrupt
|
||||
- clock-names: should have these clock names:
|
||||
"infra_sys_audio_clk",
|
||||
"top_audio_mux1_sel",
|
||||
"top_audio_mux2_sel",
|
||||
"top_audio_mux1_div",
|
||||
"top_audio_mux2_div",
|
||||
"top_audio_48k_timing",
|
||||
"top_audio_44k_timing",
|
||||
"top_audpll_mux_sel",
|
||||
"top_apll_sel",
|
||||
"top_aud1_pll_98M",
|
||||
"top_aud2_pll_90M",
|
||||
"top_hadds2_pll_98M",
|
||||
"top_hadds2_pll_294M",
|
||||
"top_audpll",
|
||||
"top_audpll_d4",
|
||||
"top_audpll_d8",
|
||||
"top_audpll_d16",
|
||||
"top_audpll_d24",
|
||||
"top_audintbus_sel",
|
||||
"clk_26m",
|
||||
"top_syspll1_d4",
|
||||
"top_aud_k1_src_sel",
|
||||
"top_aud_k2_src_sel",
|
||||
"top_aud_k3_src_sel",
|
||||
"top_aud_k4_src_sel",
|
||||
"top_aud_k5_src_sel",
|
||||
"top_aud_k6_src_sel",
|
||||
"top_aud_k1_src_div",
|
||||
"top_aud_k2_src_div",
|
||||
"top_aud_k3_src_div",
|
||||
"top_aud_k4_src_div",
|
||||
"top_aud_k5_src_div",
|
||||
"top_aud_k6_src_div",
|
||||
"top_aud_i2s1_mclk",
|
||||
"top_aud_i2s2_mclk",
|
||||
"top_aud_i2s3_mclk",
|
||||
"top_aud_i2s4_mclk",
|
||||
"top_aud_i2s5_mclk",
|
||||
"top_aud_i2s6_mclk",
|
||||
"top_asm_m_sel",
|
||||
"top_asm_h_sel",
|
||||
"top_univpll2_d4",
|
||||
"top_univpll2_d2",
|
||||
"top_syspll_d5";
|
||||
|
||||
Example:
|
||||
|
||||
afe: mt2701-afe-pcm@11220000 {
|
||||
compatible = "mediatek,mt2701-audio";
|
||||
reg = <0 0x11220000 0 0x2000>,
|
||||
<0 0x112A0000 0 0x20000>;
|
||||
interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 132 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&infracfg CLK_INFRA_AUDIO>,
|
||||
<&topckgen CLK_TOP_AUD_MUX1_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_MUX2_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_MUX1_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_MUX2_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_48K_TIMING>,
|
||||
<&topckgen CLK_TOP_AUD_44K_TIMING>,
|
||||
<&topckgen CLK_TOP_AUDPLL_MUX_SEL>,
|
||||
<&topckgen CLK_TOP_APLL_SEL>,
|
||||
<&topckgen CLK_TOP_AUD1PLL_98M>,
|
||||
<&topckgen CLK_TOP_AUD2PLL_90M>,
|
||||
<&topckgen CLK_TOP_HADDS2PLL_98M>,
|
||||
<&topckgen CLK_TOP_HADDS2PLL_294M>,
|
||||
<&topckgen CLK_TOP_AUDPLL>,
|
||||
<&topckgen CLK_TOP_AUDPLL_D4>,
|
||||
<&topckgen CLK_TOP_AUDPLL_D8>,
|
||||
<&topckgen CLK_TOP_AUDPLL_D16>,
|
||||
<&topckgen CLK_TOP_AUDPLL_D24>,
|
||||
<&topckgen CLK_TOP_AUDINTBUS_SEL>,
|
||||
<&clk26m>,
|
||||
<&topckgen CLK_TOP_SYSPLL1_D4>,
|
||||
<&topckgen CLK_TOP_AUD_K1_SRC_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_K2_SRC_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_K3_SRC_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_K4_SRC_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_K5_SRC_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_K6_SRC_SEL>,
|
||||
<&topckgen CLK_TOP_AUD_K1_SRC_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_K2_SRC_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_K3_SRC_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_K4_SRC_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_K5_SRC_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_K6_SRC_DIV>,
|
||||
<&topckgen CLK_TOP_AUD_I2S1_MCLK>,
|
||||
<&topckgen CLK_TOP_AUD_I2S2_MCLK>,
|
||||
<&topckgen CLK_TOP_AUD_I2S3_MCLK>,
|
||||
<&topckgen CLK_TOP_AUD_I2S4_MCLK>,
|
||||
<&topckgen CLK_TOP_AUD_I2S5_MCLK>,
|
||||
<&topckgen CLK_TOP_AUD_I2S6_MCLK>,
|
||||
<&topckgen CLK_TOP_ASM_M_SEL>,
|
||||
<&topckgen CLK_TOP_ASM_H_SEL>,
|
||||
<&topckgen CLK_TOP_UNIVPLL2_D4>,
|
||||
<&topckgen CLK_TOP_UNIVPLL2_D2>,
|
||||
<&topckgen CLK_TOP_SYSPLL_D5>;
|
||||
|
||||
clock-names = "infra_sys_audio_clk",
|
||||
"top_audio_mux1_sel",
|
||||
"top_audio_mux2_sel",
|
||||
"top_audio_mux1_div",
|
||||
"top_audio_mux2_div",
|
||||
"top_audio_48k_timing",
|
||||
"top_audio_44k_timing",
|
||||
"top_audpll_mux_sel",
|
||||
"top_apll_sel",
|
||||
"top_aud1_pll_98M",
|
||||
"top_aud2_pll_90M",
|
||||
"top_hadds2_pll_98M",
|
||||
"top_hadds2_pll_294M",
|
||||
"top_audpll",
|
||||
"top_audpll_d4",
|
||||
"top_audpll_d8",
|
||||
"top_audpll_d16",
|
||||
"top_audpll_d24",
|
||||
"top_audintbus_sel",
|
||||
"clk_26m",
|
||||
"top_syspll1_d4",
|
||||
"top_aud_k1_src_sel",
|
||||
"top_aud_k2_src_sel",
|
||||
"top_aud_k3_src_sel",
|
||||
"top_aud_k4_src_sel",
|
||||
"top_aud_k5_src_sel",
|
||||
"top_aud_k6_src_sel",
|
||||
"top_aud_k1_src_div",
|
||||
"top_aud_k2_src_div",
|
||||
"top_aud_k3_src_div",
|
||||
"top_aud_k4_src_div",
|
||||
"top_aud_k5_src_div",
|
||||
"top_aud_k6_src_div",
|
||||
"top_aud_i2s1_mclk",
|
||||
"top_aud_i2s2_mclk",
|
||||
"top_aud_i2s3_mclk",
|
||||
"top_aud_i2s4_mclk",
|
||||
"top_aud_i2s5_mclk",
|
||||
"top_aud_i2s6_mclk",
|
||||
"top_asm_m_sel",
|
||||
"top_asm_h_sel",
|
||||
"top_univpll2_d4",
|
||||
"top_univpll2_d2",
|
||||
"top_syspll_d5";
|
||||
};
|
|
@ -0,0 +1,43 @@
|
|||
MT2701 with CS42448 CODEC
|
||||
|
||||
Required properties:
|
||||
- compatible: "mediatek,mt2701-cs42448-machine"
|
||||
- mediatek,platform: the phandle of MT2701 ASoC platform
|
||||
- audio-routing: a list of the connections between audio
|
||||
- mediatek,audio-codec: the phandles of cs42448 codec
|
||||
- mediatek,audio-codec-bt-mrg the phandles of bt-sco dummy codec
|
||||
- pinctrl-names: Should contain only one value - "default"
|
||||
- pinctrl-0: Should specify pin control groups used for this controller.
|
||||
- i2s1-in-sel-gpio1, i2s1-in-sel-gpio2: Should specify two gpio pins to
|
||||
control I2S1-in mux.
|
||||
|
||||
Example:
|
||||
|
||||
sound:sound {
|
||||
compatible = "mediatek,mt2701-cs42448-machine";
|
||||
mediatek,platform = <&afe>;
|
||||
/* CS42448 Machine name */
|
||||
audio-routing =
|
||||
"Line Out Jack", "AOUT1L",
|
||||
"Line Out Jack", "AOUT1R",
|
||||
"Line Out Jack", "AOUT2L",
|
||||
"Line Out Jack", "AOUT2R",
|
||||
"Line Out Jack", "AOUT3L",
|
||||
"Line Out Jack", "AOUT3R",
|
||||
"Line Out Jack", "AOUT4L",
|
||||
"Line Out Jack", "AOUT4R",
|
||||
"AIN1L", "AMIC",
|
||||
"AIN1R", "AMIC",
|
||||
"AIN2L", "Tuner In",
|
||||
"AIN2R", "Tuner In",
|
||||
"AIN3L", "Satellite Tuner In",
|
||||
"AIN3R", "Satellite Tuner In",
|
||||
"AIN3L", "AUX In",
|
||||
"AIN3R", "AUX In";
|
||||
mediatek,audio-codec = <&cs42448>;
|
||||
mediatek,audio-codec-bt-mrg = <&bt_sco_codec>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&aud_pins_default>;
|
||||
i2s1-in-sel-gpio1 = <&pio 53 0>;
|
||||
i2s1-in-sel-gpio2 = <&pio 54 0>;
|
||||
};
|
|
@ -1,8 +1,9 @@
|
|||
MT8173 with RT5650 CODECS
|
||||
MT8173 with RT5650 CODECS and HDMI via I2S
|
||||
|
||||
Required properties:
|
||||
- compatible : "mediatek,mt8173-rt5650"
|
||||
- mediatek,audio-codec: the phandles of rt5650 codecs
|
||||
and of the hdmi encoder node
|
||||
- mediatek,platform: the phandle of MT8173 ASoC platform
|
||||
|
||||
Optional subnodes:
|
||||
|
@ -12,12 +13,17 @@ Required codec-capture subnode properties:
|
|||
<&rt5650 0> : Default setting. Connect rt5650 I2S1 for capture. (dai_name = rt5645-aif1)
|
||||
<&rt5650 1> : Connect rt5650 I2S2 for capture. (dai_name = rt5645-aif2)
|
||||
|
||||
- mediatek,mclk: the MCLK source
|
||||
0 : external oscillator, MCLK = 12.288M
|
||||
1 : internal source from mt8173, MCLK = sampling rate*256
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "mediatek,mt8173-rt5650";
|
||||
mediatek,audio-codec = <&rt5650>;
|
||||
mediatek,audio-codec = <&rt5650 &hdmi0>;
|
||||
mediatek,platform = <&afe>;
|
||||
mediatek,mclk = <0>;
|
||||
codec-capture {
|
||||
sound-dai = <&rt5650 1>;
|
||||
};
|
||||
|
|
|
@ -557,6 +557,10 @@ config SND_SOC_MAX98357A
|
|||
config SND_SOC_MAX98371
|
||||
tristate
|
||||
|
||||
config SND_SOC_MAX98504
|
||||
tristate "Maxim MAX98504 speaker amplifier"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_MAX9867
|
||||
tristate
|
||||
|
||||
|
|
|
@ -213,6 +213,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o
|
|||
|
||||
# Amp
|
||||
snd-soc-max9877-objs := max9877.o
|
||||
snd-soc-max98504-objs := max98504.o
|
||||
snd-soc-tpa6130a2-objs := tpa6130a2.o
|
||||
snd-soc-tas2552-objs := tas2552.o
|
||||
|
||||
|
@ -429,4 +430,5 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
|
|||
|
||||
# Amp
|
||||
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
|
||||
obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o
|
||||
obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o
|
||||
|
|
|
@ -0,0 +1,383 @@
|
|||
/*
|
||||
* MAX98504 ALSA SoC Audio driver
|
||||
*
|
||||
* Copyright 2013 - 2014 Maxim Integrated Products
|
||||
* Copyright 2016 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "max98504.h"
|
||||
|
||||
static const char * const max98504_supply_names[] = {
|
||||
"DVDD",
|
||||
"DIOVDD",
|
||||
"PVDD",
|
||||
};
|
||||
#define MAX98504_NUM_SUPPLIES ARRAY_SIZE(max98504_supply_names)
|
||||
|
||||
struct max98504_priv {
|
||||
struct regmap *regmap;
|
||||
struct regulator_bulk_data supplies[MAX98504_NUM_SUPPLIES];
|
||||
unsigned int pcm_rx_channels;
|
||||
bool brownout_enable;
|
||||
unsigned int brownout_threshold;
|
||||
unsigned int brownout_attenuation;
|
||||
unsigned int brownout_attack_hold;
|
||||
unsigned int brownout_timed_hold;
|
||||
unsigned int brownout_release_rate;
|
||||
};
|
||||
|
||||
static struct reg_default max98504_reg_defaults[] = {
|
||||
{ 0x01, 0},
|
||||
{ 0x02, 0},
|
||||
{ 0x03, 0},
|
||||
{ 0x04, 0},
|
||||
{ 0x10, 0},
|
||||
{ 0x11, 0},
|
||||
{ 0x12, 0},
|
||||
{ 0x13, 0},
|
||||
{ 0x14, 0},
|
||||
{ 0x15, 0},
|
||||
{ 0x16, 0},
|
||||
{ 0x17, 0},
|
||||
{ 0x18, 0},
|
||||
{ 0x19, 0},
|
||||
{ 0x1A, 0},
|
||||
{ 0x20, 0},
|
||||
{ 0x21, 0},
|
||||
{ 0x22, 0},
|
||||
{ 0x23, 0},
|
||||
{ 0x24, 0},
|
||||
{ 0x25, 0},
|
||||
{ 0x26, 0},
|
||||
{ 0x27, 0},
|
||||
{ 0x28, 0},
|
||||
{ 0x30, 0},
|
||||
{ 0x31, 0},
|
||||
{ 0x32, 0},
|
||||
{ 0x33, 0},
|
||||
{ 0x34, 0},
|
||||
{ 0x35, 0},
|
||||
{ 0x36, 0},
|
||||
{ 0x37, 0},
|
||||
{ 0x38, 0},
|
||||
{ 0x39, 0},
|
||||
{ 0x40, 0},
|
||||
{ 0x41, 0},
|
||||
};
|
||||
|
||||
static bool max98504_volatile_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case MAX98504_INTERRUPT_STATUS:
|
||||
case MAX98504_INTERRUPT_FLAGS:
|
||||
case MAX98504_INTERRUPT_FLAG_CLEARS:
|
||||
case MAX98504_WATCHDOG_CLEAR:
|
||||
case MAX98504_GLOBAL_ENABLE:
|
||||
case MAX98504_SOFTWARE_RESET:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool max98504_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case MAX98504_SOFTWARE_RESET:
|
||||
case MAX98504_WATCHDOG_CLEAR:
|
||||
case MAX98504_INTERRUPT_FLAG_CLEARS:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static int max98504_pcm_rx_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
|
||||
struct max98504_priv *max98504 = snd_soc_component_get_drvdata(c);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
regmap_write(max98504->regmap, MAX98504_PCM_RX_ENABLE,
|
||||
max98504->pcm_rx_channels);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
regmap_write(max98504->regmap, MAX98504_PCM_RX_ENABLE, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max98504_component_probe(struct snd_soc_component *c)
|
||||
{
|
||||
struct max98504_priv *max98504 = snd_soc_component_get_drvdata(c);
|
||||
struct regmap *map = max98504->regmap;
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(MAX98504_NUM_SUPPLIES, max98504->supplies);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
regmap_write(map, MAX98504_SOFTWARE_RESET, 0x1);
|
||||
msleep(20);
|
||||
|
||||
if (!max98504->brownout_enable)
|
||||
return 0;
|
||||
|
||||
regmap_write(map, MAX98504_PVDD_BROWNOUT_ENABLE, 0x1);
|
||||
|
||||
regmap_write(map, MAX98504_PVDD_BROWNOUT_CONFIG_1,
|
||||
(max98504->brownout_threshold & 0x1f) << 3 |
|
||||
(max98504->brownout_attenuation & 0x3));
|
||||
|
||||
regmap_write(map, MAX98504_PVDD_BROWNOUT_CONFIG_2,
|
||||
max98504->brownout_attack_hold & 0xff);
|
||||
|
||||
regmap_write(map, MAX98504_PVDD_BROWNOUT_CONFIG_3,
|
||||
max98504->brownout_timed_hold & 0xff);
|
||||
|
||||
regmap_write(map, MAX98504_PVDD_BROWNOUT_CONFIG_4,
|
||||
max98504->brownout_release_rate & 0xff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max98504_component_remove(struct snd_soc_component *c)
|
||||
{
|
||||
struct max98504_priv *max98504 = snd_soc_component_get_drvdata(c);
|
||||
|
||||
regulator_bulk_disable(MAX98504_NUM_SUPPLIES, max98504->supplies);
|
||||
}
|
||||
|
||||
static const char *spk_source_mux_text[] = {
|
||||
"PCM Monomix", "Analog In", "PDM Left", "PDM Right"
|
||||
};
|
||||
|
||||
static const struct soc_enum spk_source_mux_enum =
|
||||
SOC_ENUM_SINGLE(MAX98504_SPEAKER_SOURCE_SELECT,
|
||||
0, ARRAY_SIZE(spk_source_mux_text),
|
||||
spk_source_mux_text);
|
||||
|
||||
static const struct snd_kcontrol_new spk_source_mux =
|
||||
SOC_DAPM_ENUM("SPK Source", spk_source_mux_enum);
|
||||
|
||||
static const struct snd_soc_dapm_route max98504_dapm_routes[] = {
|
||||
{ "SPKOUT", NULL, "Global Enable" },
|
||||
{ "SPK Source", "PCM Monomix", "DAC PCM" },
|
||||
{ "SPK Source", "Analog In", "AIN" },
|
||||
{ "SPK Source", "PDM Left", "DAC PDM" },
|
||||
{ "SPK Source", "PDM Right", "DAC PDM" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget max98504_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("Global Enable", MAX98504_GLOBAL_ENABLE,
|
||||
0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_INPUT("AIN"),
|
||||
SND_SOC_DAPM_AIF_OUT("AIF2OUTL", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("AIF2OUTR", "AIF2 Capture", 1, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_DAC_E("DAC PCM", NULL, SND_SOC_NOPM, 0, 0,
|
||||
max98504_pcm_rx_ev,
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
|
||||
SND_SOC_DAPM_DAC("DAC PDM", NULL, MAX98504_PDM_RX_ENABLE, 0, 0),
|
||||
SND_SOC_DAPM_MUX("SPK Source", SND_SOC_NOPM, 0, 0, &spk_source_mux),
|
||||
SND_SOC_DAPM_REG(snd_soc_dapm_spk, "SPKOUT",
|
||||
MAX98504_SPEAKER_ENABLE, 0, 1, 1, 0),
|
||||
};
|
||||
|
||||
static int max98504_set_tdm_slot(struct snd_soc_dai *dai,
|
||||
unsigned int tx_mask, unsigned int rx_mask,
|
||||
int slots, int slot_width)
|
||||
{
|
||||
struct max98504_priv *max98504 = snd_soc_dai_get_drvdata(dai);
|
||||
struct regmap *map = max98504->regmap;
|
||||
|
||||
|
||||
switch (dai->id) {
|
||||
case MAX98504_DAI_ID_PCM:
|
||||
regmap_write(map, MAX98504_PCM_TX_ENABLE, tx_mask);
|
||||
max98504->pcm_rx_channels = rx_mask;
|
||||
break;
|
||||
|
||||
case MAX98504_DAI_ID_PDM:
|
||||
regmap_write(map, MAX98504_PDM_TX_ENABLE, tx_mask);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int max98504_set_channel_map(struct snd_soc_dai *dai,
|
||||
unsigned int tx_num, unsigned int *tx_slot,
|
||||
unsigned int rx_num, unsigned int *rx_slot)
|
||||
{
|
||||
struct max98504_priv *max98504 = snd_soc_dai_get_drvdata(dai);
|
||||
struct regmap *map = max98504->regmap;
|
||||
unsigned int i, sources = 0;
|
||||
|
||||
for (i = 0; i < tx_num; i++)
|
||||
if (tx_slot[i])
|
||||
sources |= (1 << i);
|
||||
|
||||
switch (dai->id) {
|
||||
case MAX98504_DAI_ID_PCM:
|
||||
regmap_write(map, MAX98504_PCM_TX_CHANNEL_SOURCES,
|
||||
sources);
|
||||
break;
|
||||
|
||||
case MAX98504_DAI_ID_PDM:
|
||||
regmap_write(map, MAX98504_PDM_TX_CONTROL, sources);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
regmap_write(map, MAX98504_MEASUREMENT_ENABLE, sources ? 0x3 : 0x01);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops max98504_dai_ops = {
|
||||
.set_tdm_slot = max98504_set_tdm_slot,
|
||||
.set_channel_map = max98504_set_channel_map,
|
||||
};
|
||||
|
||||
#define MAX98504_FORMATS (SNDRV_PCM_FMTBIT_S8|SNDRV_PCM_FMTBIT_S16_LE|\
|
||||
SNDRV_PCM_FMTBIT_S24_LE|SNDRV_PCM_FMTBIT_S32_LE)
|
||||
#define MAX98504_PDM_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
|
||||
SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100|\
|
||||
SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_88200|\
|
||||
SNDRV_PCM_RATE_96000)
|
||||
|
||||
static struct snd_soc_dai_driver max98504_dai[] = {
|
||||
/* TODO: Add the PCM interface definitions */
|
||||
{
|
||||
.name = "max98504-aif2",
|
||||
.id = MAX98504_DAI_ID_PDM,
|
||||
.playback = {
|
||||
.stream_name = "AIF2 Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = MAX98504_PDM_RATES,
|
||||
.formats = MAX98504_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "AIF2 Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = MAX98504_PDM_RATES,
|
||||
.formats = MAX98504_FORMATS,
|
||||
},
|
||||
.ops = &max98504_dai_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver max98504_component_driver = {
|
||||
.probe = max98504_component_probe,
|
||||
.remove = max98504_component_remove,
|
||||
.dapm_widgets = max98504_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(max98504_dapm_widgets),
|
||||
.dapm_routes = max98504_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(max98504_dapm_routes),
|
||||
};
|
||||
|
||||
static const struct regmap_config max98504_regmap = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
.max_register = MAX98504_MAX_REGISTER,
|
||||
.reg_defaults = max98504_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(max98504_reg_defaults),
|
||||
.volatile_reg = max98504_volatile_register,
|
||||
.readable_reg = max98504_readable_register,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static int max98504_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct max98504_priv *max98504;
|
||||
int i, ret;
|
||||
|
||||
max98504 = devm_kzalloc(dev, sizeof(*max98504), GFP_KERNEL);
|
||||
if (!max98504)
|
||||
return -ENOMEM;
|
||||
|
||||
if (node) {
|
||||
if (!of_property_read_u32(node, "maxim,brownout-threshold",
|
||||
&max98504->brownout_threshold))
|
||||
max98504->brownout_enable = true;
|
||||
|
||||
of_property_read_u32(node, "maxim,brownout-attenuation",
|
||||
&max98504->brownout_attenuation);
|
||||
of_property_read_u32(node, "maxim,brownout-attack-hold-ms",
|
||||
&max98504->brownout_attack_hold);
|
||||
of_property_read_u32(node, "maxim,brownout-timed-hold-ms",
|
||||
&max98504->brownout_timed_hold);
|
||||
of_property_read_u32(node, "maxim,brownout-release-rate-ms",
|
||||
&max98504->brownout_release_rate);
|
||||
}
|
||||
|
||||
max98504->regmap = devm_regmap_init_i2c(client, &max98504_regmap);
|
||||
if (IS_ERR(max98504->regmap)) {
|
||||
ret = PTR_ERR(max98504->regmap);
|
||||
dev_err(&client->dev, "regmap initialization failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX98504_NUM_SUPPLIES; i++)
|
||||
max98504->supplies[i].supply = max98504_supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(dev, MAX98504_NUM_SUPPLIES,
|
||||
max98504->supplies);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
i2c_set_clientdata(client, max98504);
|
||||
|
||||
return devm_snd_soc_register_component(dev, &max98504_component_driver,
|
||||
max98504_dai, ARRAY_SIZE(max98504_dai));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id max98504_of_match[] = {
|
||||
{ .compatible = "maxim,max98504" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max98504_of_match);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id max98504_i2c_id[] = {
|
||||
{ "max98504" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max98504_i2c_id);
|
||||
|
||||
static struct i2c_driver max98504_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "max98504",
|
||||
.of_match_table = of_match_ptr(max98504_of_match),
|
||||
},
|
||||
.probe = max98504_i2c_probe,
|
||||
.id_table = max98504_i2c_id,
|
||||
};
|
||||
module_i2c_driver(max98504_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC MAX98504 driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* MAX98504 ALSA SoC Audio driver
|
||||
*
|
||||
* Copyright 2011 - 2012 Maxim Integrated Products
|
||||
* Copyright 2016 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#ifndef MAX98504_H_
|
||||
#define MAX98504_H_
|
||||
|
||||
/*
|
||||
* MAX98504 Register Definitions
|
||||
*/
|
||||
#define MAX98504_INTERRUPT_STATUS 0x01
|
||||
#define MAX98504_INTERRUPT_FLAGS 0x02
|
||||
#define MAX98504_INTERRUPT_ENABLE 0x03
|
||||
#define MAX98504_INTERRUPT_FLAG_CLEARS 0x04
|
||||
#define MAX98504_GPIO_ENABLE 0x10
|
||||
#define MAX98504_GPIO_CONFIG 0x11
|
||||
#define MAX98504_WATCHDOG_ENABLE 0x12
|
||||
#define MAX98504_WATCHDOG_CONFIG 0x13
|
||||
#define MAX98504_WATCHDOG_CLEAR 0x14
|
||||
#define MAX98504_CLOCK_MONITOR_ENABLE 0x15
|
||||
#define MAX98504_PVDD_BROWNOUT_ENABLE 0x16
|
||||
#define MAX98504_PVDD_BROWNOUT_CONFIG_1 0x17
|
||||
#define MAX98504_PVDD_BROWNOUT_CONFIG_2 0x18
|
||||
#define MAX98504_PVDD_BROWNOUT_CONFIG_3 0x19
|
||||
#define MAX98504_PVDD_BROWNOUT_CONFIG_4 0x1a
|
||||
#define MAX98504_PCM_RX_ENABLE 0x20
|
||||
#define MAX98504_PCM_TX_ENABLE 0x21
|
||||
#define MAX98504_PCM_TX_HIZ_CONTROL 0x22
|
||||
#define MAX98504_PCM_TX_CHANNEL_SOURCES 0x23
|
||||
#define MAX98504_PCM_MODE_CONFIG 0x24
|
||||
#define MAX98504_PCM_DSP_CONFIG 0x25
|
||||
#define MAX98504_PCM_CLOCK_SETUP 0x26
|
||||
#define MAX98504_PCM_SAMPLE_RATE_SETUP 0x27
|
||||
#define MAX98504_PCM_TO_SPEAKER_MONOMIX 0x28
|
||||
#define MAX98504_PDM_TX_ENABLE 0x30
|
||||
#define MAX98504_PDM_TX_HIZ_CONTROL 0x31
|
||||
#define MAX98504_PDM_TX_CONTROL 0x32
|
||||
#define MAX98504_PDM_RX_ENABLE 0x33
|
||||
#define MAX98504_SPEAKER_ENABLE 0x34
|
||||
#define MAX98504_SPEAKER_SOURCE_SELECT 0x35
|
||||
#define MAX98504_MEASUREMENT_ENABLE 0x36
|
||||
#define MAX98504_ANALOGUE_INPUT_GAIN 0x37
|
||||
#define MAX98504_TEMPERATURE_LIMIT_CONFIG 0x38
|
||||
#define MAX98504_GLOBAL_ENABLE 0x40
|
||||
#define MAX98504_SOFTWARE_RESET 0x41
|
||||
#define MAX98504_REV_ID 0x7fff
|
||||
|
||||
#define MAX98504_MAX_REGISTER 0x7fff
|
||||
|
||||
#define MAX98504_DAI_ID_PCM 1
|
||||
#define MAX98504_DAI_ID_PDM 2
|
||||
|
||||
#endif /* MAX98504_H_ */
|
|
@ -32,6 +32,4 @@
|
|||
#define MAX9877_BYPASS (1 << 6)
|
||||
#define MAX9877_SHDN (1 << 7)
|
||||
|
||||
extern int max9877_add_controls(struct snd_soc_codec *codec);
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -93,12 +93,21 @@
|
|||
#define NAU8825_REG_CHARGE_PUMP_INPUT_READ 0x81
|
||||
#define NAU8825_REG_GENERAL_STATUS 0x82
|
||||
#define NAU8825_REG_MAX NAU8825_REG_GENERAL_STATUS
|
||||
/* 16-bit control register address, and 16-bits control register data */
|
||||
#define NAU8825_REG_ADDR_LEN 16
|
||||
#define NAU8825_REG_DATA_LEN 16
|
||||
|
||||
/* ENA_CTRL (0x1) */
|
||||
#define NAU8825_ENABLE_DACR_SFT 10
|
||||
#define NAU8825_ENABLE_DACR (1 << NAU8825_ENABLE_DACR_SFT)
|
||||
#define NAU8825_ENABLE_DACL_SFT 9
|
||||
#define NAU8825_ENABLE_DACL (1 << NAU8825_ENABLE_DACL_SFT)
|
||||
#define NAU8825_ENABLE_ADC_SFT 8
|
||||
#define NAU8825_ENABLE_ADC (1 << NAU8825_ENABLE_ADC_SFT)
|
||||
#define NAU8825_ENABLE_ADC_CLK_SFT 7
|
||||
#define NAU8825_ENABLE_ADC_CLK (1 << NAU8825_ENABLE_ADC_CLK_SFT)
|
||||
#define NAU8825_ENABLE_DAC_CLK_SFT 6
|
||||
#define NAU8825_ENABLE_DAC_CLK (1 << NAU8825_ENABLE_DAC_CLK_SFT)
|
||||
#define NAU8825_ENABLE_SAR_SFT 1
|
||||
|
||||
/* CLK_DIVIDER (0x3) */
|
||||
|
@ -113,20 +122,28 @@
|
|||
|
||||
/* FLL3 (0x06) */
|
||||
#define NAU8825_FLL_INTEGER_MASK (0x3ff << 0)
|
||||
#define NAU8825_FLL_CLK_SRC_SFT 10
|
||||
#define NAU8825_FLL_CLK_SRC_MASK (0x3 << NAU8825_FLL_CLK_SRC_SFT)
|
||||
#define NAU8825_FLL_CLK_SRC_MCLK (0 << NAU8825_FLL_CLK_SRC_SFT)
|
||||
#define NAU8825_FLL_CLK_SRC_BLK (0x2 << NAU8825_FLL_CLK_SRC_SFT)
|
||||
#define NAU8825_FLL_CLK_SRC_FS (0x3 << NAU8825_FLL_CLK_SRC_SFT)
|
||||
|
||||
/* FLL4 (0x07) */
|
||||
#define NAU8825_FLL_REF_DIV_MASK (0x3 << 10)
|
||||
|
||||
/* FLL5 (0x08) */
|
||||
#define NAU8825_FLL_FILTER_SW_MASK (0x1 << 14)
|
||||
#define NAU8825_FLL_PDB_DAC_EN (0x1 << 15)
|
||||
#define NAU8825_FLL_LOOP_FTR_EN (0x1 << 14)
|
||||
#define NAU8825_FLL_CLK_SW_MASK (0x1 << 13)
|
||||
#define NAU8825_FLL_CLK_SW_N2 (0x1 << 13)
|
||||
#define NAU8825_FLL_CLK_SW_REF (0x0 << 13)
|
||||
#define NAU8825_FLL_FTR_SW_MASK (0x1 << 12)
|
||||
#define NAU8825_FLL_FTR_SW_ACCU (0x1 << 12)
|
||||
#define NAU8825_FLL_FTR_SW_FILTER (0x0 << 12)
|
||||
|
||||
/* FLL6 (0x9) */
|
||||
#define NAU8825_DCO_EN_MASK (0x1 << 15)
|
||||
#define NAU8825_DCO_EN (0x1 << 15)
|
||||
#define NAU8825_DCO_DIS (0x0 << 15)
|
||||
#define NAU8825_SDM_EN_MASK (0x1 << 14)
|
||||
#define NAU8825_SDM_EN (0x1 << 14)
|
||||
#define NAU8825_SDM_DIS (0x0 << 14)
|
||||
|
||||
/* HSD_CTRL (0xc) */
|
||||
#define NAU8825_HSD_AUTO_MODE (1 << 6)
|
||||
|
@ -136,6 +153,7 @@
|
|||
|
||||
/* JACK_DET_CTRL (0xd) */
|
||||
#define NAU8825_JACK_DET_RESTART (1 << 9)
|
||||
#define NAU8825_JACK_DET_DB_BYPASS (1 << 8)
|
||||
#define NAU8825_JACK_INSERT_DEBOUNCE_SFT 5
|
||||
#define NAU8825_JACK_INSERT_DEBOUNCE_MASK (0x7 << NAU8825_JACK_INSERT_DEBOUNCE_SFT)
|
||||
#define NAU8825_JACK_EJECT_DEBOUNCE_SFT 2
|
||||
|
@ -145,9 +163,11 @@
|
|||
/* INTERRUPT_MASK (0xf) */
|
||||
#define NAU8825_IRQ_OUTPUT_EN (1 << 11)
|
||||
#define NAU8825_IRQ_HEADSET_COMPLETE_EN (1 << 10)
|
||||
#define NAU8825_IRQ_RMS_EN (1 << 8)
|
||||
#define NAU8825_IRQ_KEY_RELEASE_EN (1 << 7)
|
||||
#define NAU8825_IRQ_KEY_SHORT_PRESS_EN (1 << 5)
|
||||
#define NAU8825_IRQ_EJECT_EN (1 << 2)
|
||||
#define NAU8825_IRQ_INSERT_EN (1 << 0)
|
||||
|
||||
/* IRQ_STATUS (0x10) */
|
||||
#define NAU8825_HEADSET_COMPLETION_IRQ (1 << 10)
|
||||
|
@ -168,6 +188,7 @@
|
|||
#define NAU8825_IRQ_KEY_RELEASE_DIS (1 << 7)
|
||||
#define NAU8825_IRQ_KEY_SHORT_PRESS_DIS (1 << 5)
|
||||
#define NAU8825_IRQ_EJECT_DIS (1 << 2)
|
||||
#define NAU8825_IRQ_INSERT_DIS (1 << 0)
|
||||
|
||||
/* SAR_CTRL (0x13) */
|
||||
#define NAU8825_SAR_ADC_EN_SFT 12
|
||||
|
@ -217,10 +238,21 @@
|
|||
|
||||
/* I2S_PCM_CTRL2 (0x1d) */
|
||||
#define NAU8825_I2S_TRISTATE (1 << 15) /* 0 - normal mode, 1 - Hi-Z output */
|
||||
#define NAU8825_I2S_DRV_SFT 12
|
||||
#define NAU8825_I2S_DRV_MASK (0x3 << NAU8825_I2S_DRV_SFT)
|
||||
#define NAU8825_I2S_MS_SFT 3
|
||||
#define NAU8825_I2S_MS_MASK (1 << NAU8825_I2S_MS_SFT)
|
||||
#define NAU8825_I2S_MS_MASTER (1 << NAU8825_I2S_MS_SFT)
|
||||
#define NAU8825_I2S_MS_SLAVE (0 << NAU8825_I2S_MS_SFT)
|
||||
#define NAU8825_I2S_BLK_DIV_MASK 0x7
|
||||
|
||||
/* BIQ_CTRL (0x20) */
|
||||
#define NAU8825_BIQ_WRT_SFT 4
|
||||
#define NAU8825_BIQ_WRT_EN (1 << NAU8825_BIQ_WRT_SFT)
|
||||
#define NAU8825_BIQ_PATH_SFT 0
|
||||
#define NAU8825_BIQ_PATH_MASK (1 << NAU8825_BIQ_PATH_SFT)
|
||||
#define NAU8825_BIQ_PATH_ADC (0 << NAU8825_BIQ_PATH_SFT)
|
||||
#define NAU8825_BIQ_PATH_DAC (1 << NAU8825_BIQ_PATH_SFT)
|
||||
|
||||
/* ADC_RATE (0x2b) */
|
||||
#define NAU8825_ADC_SYNC_DOWN_SFT 0
|
||||
|
@ -239,22 +271,72 @@
|
|||
#define NAU8825_DAC_OVERSAMPLE_128 2
|
||||
#define NAU8825_DAC_OVERSAMPLE_32 4
|
||||
|
||||
/* ADC_DGAIN_CTRL (0x30) */
|
||||
#define NAU8825_ADC_DIG_VOL_MASK 0xff
|
||||
|
||||
/* MUTE_CTRL (0x31) */
|
||||
#define NAU8825_DAC_ZERO_CROSSING_EN (1 << 9)
|
||||
#define NAU8825_DAC_SOFT_MUTE (1 << 9)
|
||||
|
||||
/* HSVOL_CTRL (0x32) */
|
||||
#define NAU8825_HP_MUTE (1 << 15)
|
||||
#define NAU8825_HP_MUTE_AUTO (1 << 14)
|
||||
#define NAU8825_HPL_MUTE (1 << 13)
|
||||
#define NAU8825_HPR_MUTE (1 << 12)
|
||||
#define NAU8825_HPL_VOL_SFT 6
|
||||
#define NAU8825_HPL_VOL_MASK (0x3f << NAU8825_HPL_VOL_SFT)
|
||||
#define NAU8825_HPR_VOL_SFT 0
|
||||
#define NAU8825_HPR_VOL_MASK (0x3f << NAU8825_HPR_VOL_SFT)
|
||||
#define NAU8825_HP_VOL_MIN 0x36
|
||||
|
||||
/* DACL_CTRL (0x33) */
|
||||
#define NAU8825_DACL_CH_SEL_SFT 9
|
||||
#define NAU8825_DACL_CH_SEL_MASK (0x1 << NAU8825_DACL_CH_SEL_SFT)
|
||||
#define NAU8825_DACL_CH_SEL_L (0x0 << NAU8825_DACL_CH_SEL_SFT)
|
||||
#define NAU8825_DACL_CH_SEL_R (0x1 << NAU8825_DACL_CH_SEL_SFT)
|
||||
#define NAU8825_DACL_CH_VOL_MASK 0xff
|
||||
|
||||
/* DACR_CTRL (0x34) */
|
||||
#define NAU8825_DACR_CH_SEL_SFT 9
|
||||
#define NAU8825_DACR_CH_SEL_MASK (0x1 << NAU8825_DACR_CH_SEL_SFT)
|
||||
#define NAU8825_DACR_CH_SEL_L (0x0 << NAU8825_DACR_CH_SEL_SFT)
|
||||
#define NAU8825_DACR_CH_SEL_R (0x1 << NAU8825_DACR_CH_SEL_SFT)
|
||||
#define NAU8825_DACR_CH_VOL_MASK 0xff
|
||||
|
||||
/* IMM_MODE_CTRL (0x4C) */
|
||||
#define NAU8825_IMM_THD_SFT 8
|
||||
#define NAU8825_IMM_THD_MASK (0x3f << NAU8825_IMM_THD_SFT)
|
||||
#define NAU8825_IMM_GEN_VOL_SFT 6
|
||||
#define NAU8825_IMM_GEN_VOL_MASK (0x3 << NAU8825_IMM_GEN_VOL_SFT)
|
||||
#define NAU8825_IMM_GEN_VOL_1_2nd (0x0 << NAU8825_IMM_GEN_VOL_SFT)
|
||||
#define NAU8825_IMM_GEN_VOL_1_4th (0x1 << NAU8825_IMM_GEN_VOL_SFT)
|
||||
#define NAU8825_IMM_GEN_VOL_1_8th (0x2 << NAU8825_IMM_GEN_VOL_SFT)
|
||||
#define NAU8825_IMM_GEN_VOL_1_16th (0x3 << NAU8825_IMM_GEN_VOL_SFT)
|
||||
|
||||
#define NAU8825_IMM_CYC_SFT 4
|
||||
#define NAU8825_IMM_CYC_MASK (0x3 << NAU8825_IMM_CYC_SFT)
|
||||
#define NAU8825_IMM_CYC_1024 (0x0 << NAU8825_IMM_CYC_SFT)
|
||||
#define NAU8825_IMM_CYC_2048 (0x1 << NAU8825_IMM_CYC_SFT)
|
||||
#define NAU8825_IMM_CYC_4096 (0x2 << NAU8825_IMM_CYC_SFT)
|
||||
#define NAU8825_IMM_CYC_8192 (0x3 << NAU8825_IMM_CYC_SFT)
|
||||
#define NAU8825_IMM_EN (1 << 3)
|
||||
#define NAU8825_IMM_DAC_SRC_MASK 0x7
|
||||
#define NAU8825_IMM_DAC_SRC_BIQ 0x0
|
||||
#define NAU8825_IMM_DAC_SRC_DRC 0x1
|
||||
#define NAU8825_IMM_DAC_SRC_MIX 0x2
|
||||
#define NAU8825_IMM_DAC_SRC_SIN 0x3
|
||||
|
||||
/* CLASSG_CTRL (0x50) */
|
||||
#define NAU8825_CLASSG_TIMER_SFT 8
|
||||
#define NAU8825_CLASSG_TIMER_MASK (0x3f << NAU8825_CLASSG_TIMER_SFT)
|
||||
#define NAU8825_CLASSG_TIMER_1ms (0x1 << NAU8825_CLASSG_TIMER_SFT)
|
||||
#define NAU8825_CLASSG_TIMER_2ms (0x2 << NAU8825_CLASSG_TIMER_SFT)
|
||||
#define NAU8825_CLASSG_TIMER_8ms (0x4 << NAU8825_CLASSG_TIMER_SFT)
|
||||
#define NAU8825_CLASSG_TIMER_16ms (0x8 << NAU8825_CLASSG_TIMER_SFT)
|
||||
#define NAU8825_CLASSG_TIMER_32ms (0x10 << NAU8825_CLASSG_TIMER_SFT)
|
||||
#define NAU8825_CLASSG_TIMER_64ms (0x20 << NAU8825_CLASSG_TIMER_SFT)
|
||||
#define NAU8825_CLASSG_LDAC_EN (0x1 << 2)
|
||||
#define NAU8825_CLASSG_RDAC_EN (0x1 << 1)
|
||||
#define NAU8825_CLASSG_EN (1 << 0)
|
||||
|
||||
/* I2C_DEVICE_ID (0x58) */
|
||||
|
@ -263,7 +345,12 @@
|
|||
#define NAU8825_SOFTWARE_ID_NAU8825 0x0
|
||||
|
||||
/* BIAS_ADJ (0x66) */
|
||||
#define NAU8825_BIAS_TESTDAC_EN (0x3 << 8)
|
||||
#define NAU8825_BIAS_HPR_IMP (1 << 15)
|
||||
#define NAU8825_BIAS_HPL_IMP (1 << 14)
|
||||
#define NAU8825_BIAS_TESTDAC_SFT 8
|
||||
#define NAU8825_BIAS_TESTDAC_EN (0x3 << NAU8825_BIAS_TESTDAC_SFT)
|
||||
#define NAU8825_BIAS_TESTDACR_EN (0x2 << NAU8825_BIAS_TESTDAC_SFT)
|
||||
#define NAU8825_BIAS_TESTDACL_EN (0x1 << NAU8825_BIAS_TESTDAC_SFT)
|
||||
#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)
|
||||
|
@ -282,6 +369,11 @@
|
|||
#define NAU8825_POWERUP_ADCL (1 << 6)
|
||||
|
||||
/* RDAC (0x73) */
|
||||
#define NAU8825_RDAC_FS_BCLK_ENB (1 << 15)
|
||||
#define NAU8825_RDAC_EN_SFT 12
|
||||
#define NAU8825_RDAC_EN (0x3 << NAU8825_RDAC_EN_SFT)
|
||||
#define NAU8825_RDAC_CLK_EN_SFT 8
|
||||
#define NAU8825_RDAC_CLK_EN (0x3 << NAU8825_RDAC_CLK_EN_SFT)
|
||||
#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
|
||||
|
@ -318,8 +410,21 @@
|
|||
|
||||
/* System Clock Source */
|
||||
enum {
|
||||
NAU8825_CLK_MCLK = 0,
|
||||
NAU8825_CLK_DIS = 0,
|
||||
NAU8825_CLK_MCLK,
|
||||
NAU8825_CLK_INTERNAL,
|
||||
NAU8825_CLK_FLL_MCLK,
|
||||
NAU8825_CLK_FLL_BLK,
|
||||
NAU8825_CLK_FLL_FS,
|
||||
};
|
||||
|
||||
/* Cross talk detection state */
|
||||
enum {
|
||||
NAU8825_XTALK_PREPARE = 0,
|
||||
NAU8825_XTALK_HPR_R2L,
|
||||
NAU8825_XTALK_HPL_R2L,
|
||||
NAU8825_XTALK_IMM,
|
||||
NAU8825_XTALK_DONE,
|
||||
};
|
||||
|
||||
struct nau8825 {
|
||||
|
@ -328,6 +433,8 @@ struct nau8825 {
|
|||
struct snd_soc_dapm_context *dapm;
|
||||
struct snd_soc_jack *jack;
|
||||
struct clk *mclk;
|
||||
struct work_struct xtalk_work;
|
||||
struct semaphore xtalk_sem;
|
||||
int irq;
|
||||
int mclk_freq; /* 0 - mclk is disabled */
|
||||
int button_pressed;
|
||||
|
@ -346,6 +453,12 @@ struct nau8825 {
|
|||
int key_debounce;
|
||||
int jack_insert_debounce;
|
||||
int jack_eject_debounce;
|
||||
int high_imped;
|
||||
int xtalk_state;
|
||||
int xtalk_event;
|
||||
int xtalk_event_mask;
|
||||
bool xtalk_protect;
|
||||
int imp_rms[NAU8825_XTALK_IMM];
|
||||
};
|
||||
|
||||
int nau8825_enable_jack_detect(struct snd_soc_codec *codec,
|
||||
|
|
|
@ -1,15 +1,40 @@
|
|||
config SND_SOC_MEDIATEK
|
||||
tristate "ASoC support for Mediatek chip"
|
||||
tristate
|
||||
|
||||
config SND_SOC_MT2701
|
||||
tristate "ASoC support for Mediatek MT2701 chip"
|
||||
depends on ARCH_MEDIATEK
|
||||
select SND_SOC_MEDIATEK
|
||||
help
|
||||
This adds ASoC platform driver support for Mediatek chip
|
||||
This adds ASoC driver for Mediatek MT2701 boards
|
||||
that can be used with other codecs.
|
||||
Select Y if you have such device.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_MT2701_CS42448
|
||||
tristate "ASoc Audio driver for MT2701 with CS42448 codec"
|
||||
depends on SND_SOC_MT2701
|
||||
select SND_SOC_CS42XX8_I2C
|
||||
select SND_SOC_BT_SCO
|
||||
help
|
||||
This adds ASoC driver for Mediatek MT2701 boards
|
||||
with the CS42448 codecs.
|
||||
Select Y if you have such device.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_MT8173
|
||||
tristate "ASoC support for Mediatek MT8173 chip"
|
||||
depends on ARCH_MEDIATEK
|
||||
select SND_SOC_MEDIATEK
|
||||
help
|
||||
This adds ASoC platform driver support for Mediatek MT8173 chip
|
||||
that can be used with other codecs.
|
||||
Select Y if you have such device.
|
||||
Ex: MT8173
|
||||
|
||||
config SND_SOC_MT8173_MAX98090
|
||||
tristate "ASoC Audio driver for MT8173 with MAX98090 codec"
|
||||
depends on SND_SOC_MEDIATEK && I2C
|
||||
depends on SND_SOC_MT8173 && I2C
|
||||
select SND_SOC_MAX98090
|
||||
help
|
||||
This adds ASoC driver for Mediatek MT8173 boards
|
||||
|
@ -19,8 +44,9 @@ config SND_SOC_MT8173_MAX98090
|
|||
|
||||
config SND_SOC_MT8173_RT5650
|
||||
tristate "ASoC Audio driver for MT8173 with RT5650 codec"
|
||||
depends on SND_SOC_MEDIATEK && I2C
|
||||
depends on SND_SOC_MT8173 && I2C
|
||||
select SND_SOC_RT5645
|
||||
select SND_SOC_HDMI_CODEC
|
||||
help
|
||||
This adds ASoC driver for Mediatek MT8173 boards
|
||||
with the RT5650 audio codec.
|
||||
|
@ -29,7 +55,7 @@ config SND_SOC_MT8173_RT5650
|
|||
|
||||
config SND_SOC_MT8173_RT5650_RT5514
|
||||
tristate "ASoC Audio driver for MT8173 with RT5650 RT5514 codecs"
|
||||
depends on SND_SOC_MEDIATEK && I2C
|
||||
depends on SND_SOC_MT8173 && I2C
|
||||
select SND_SOC_RT5645
|
||||
select SND_SOC_RT5514
|
||||
help
|
||||
|
@ -40,7 +66,7 @@ config SND_SOC_MT8173_RT5650_RT5514
|
|||
|
||||
config SND_SOC_MT8173_RT5650_RT5676
|
||||
tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs"
|
||||
depends on SND_SOC_MEDIATEK && I2C
|
||||
depends on SND_SOC_MT8173 && I2C
|
||||
select SND_SOC_RT5645
|
||||
select SND_SOC_RT5677
|
||||
select SND_SOC_HDMI_CODEC
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
# MTK Platform Support
|
||||
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
|
||||
obj-$(CONFIG_SND_SOC_MEDIATEK) += common/
|
||||
obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
|
||||
obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#
|
||||
# Copyright (C) 2015 MediaTek Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# platform driver
|
||||
snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o
|
||||
obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o
|
|
@ -0,0 +1,379 @@
|
|||
/*
|
||||
* mtk-afe-fe-dais.c -- Mediatek afe fe dai operator
|
||||
*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: Garlic Tseng <garlic.tseng@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/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/soc.h>
|
||||
#include "mtk-afe-fe-dai.h"
|
||||
#include "mtk-base-afe.h"
|
||||
|
||||
#define AFE_BASE_END_OFFSET 8
|
||||
|
||||
int mtk_regmap_update_bits(struct regmap *map, int reg, unsigned int mask,
|
||||
unsigned int val)
|
||||
{
|
||||
if (reg < 0)
|
||||
return 0;
|
||||
return regmap_update_bits(map, reg, mask, val);
|
||||
}
|
||||
|
||||
int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)
|
||||
{
|
||||
if (reg < 0)
|
||||
return 0;
|
||||
return regmap_write(map, reg, val);
|
||||
}
|
||||
|
||||
int mtk_afe_fe_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
int memif_num = rtd->cpu_dai->id;
|
||||
struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
|
||||
const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware;
|
||||
int ret;
|
||||
|
||||
memif->substream = substream;
|
||||
|
||||
snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
|
||||
/* enable agent */
|
||||
mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,
|
||||
1 << memif->data->agent_disable_shift,
|
||||
0 << memif->data->agent_disable_shift);
|
||||
|
||||
snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware);
|
||||
|
||||
/*
|
||||
* Capture cannot use ping-pong buffer since hw_ptr at IRQ may be
|
||||
* smaller than period_size due to AFE's internal buffer.
|
||||
* This easily leads to overrun when avail_min is period_size.
|
||||
* One more period can hold the possible unread buffer.
|
||||
*/
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
|
||||
int periods_max = mtk_afe_hardware->periods_max;
|
||||
|
||||
ret = snd_pcm_hw_constraint_minmax(runtime,
|
||||
SNDRV_PCM_HW_PARAM_PERIODS,
|
||||
3, periods_max);
|
||||
if (ret < 0) {
|
||||
dev_err(afe->dev, "hw_constraint_minmax failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = snd_pcm_hw_constraint_integer(runtime,
|
||||
SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
if (ret < 0)
|
||||
dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
|
||||
|
||||
/* dynamic allocate irq to memif */
|
||||
if (memif->irq_usage < 0) {
|
||||
int irq_id = mtk_dynamic_irq_acquire(afe);
|
||||
|
||||
if (irq_id != afe->irqs_size) {
|
||||
/* link */
|
||||
memif->irq_usage = irq_id;
|
||||
} else {
|
||||
dev_err(afe->dev, "%s() error: no more asys irq\n",
|
||||
__func__);
|
||||
ret = -EBUSY;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_fe_startup);
|
||||
|
||||
void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
|
||||
int irq_id;
|
||||
|
||||
irq_id = memif->irq_usage;
|
||||
|
||||
mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,
|
||||
1 << memif->data->agent_disable_shift,
|
||||
1 << memif->data->agent_disable_shift);
|
||||
|
||||
if (!memif->const_irq) {
|
||||
mtk_dynamic_irq_release(afe, irq_id);
|
||||
memif->irq_usage = -1;
|
||||
memif->substream = NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_fe_shutdown);
|
||||
|
||||
int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
|
||||
int msb_at_bit33 = 0;
|
||||
int ret, fs = 0;
|
||||
|
||||
ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
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 */
|
||||
mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base,
|
||||
memif->phys_buf_addr);
|
||||
/* end */
|
||||
mtk_regmap_write(afe->regmap,
|
||||
memif->data->reg_ofs_base + AFE_BASE_END_OFFSET,
|
||||
memif->phys_buf_addr + memif->buffer_size - 1);
|
||||
|
||||
/* set MSB to 33-bit */
|
||||
mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg,
|
||||
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;
|
||||
|
||||
mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,
|
||||
1 << memif->data->mono_shift,
|
||||
mono << memif->data->mono_shift);
|
||||
}
|
||||
|
||||
/* set rate */
|
||||
if (memif->data->fs_shift < 0)
|
||||
return 0;
|
||||
|
||||
fs = afe->memif_fs(substream, params_rate(params));
|
||||
|
||||
if (fs < 0)
|
||||
return -EINVAL;
|
||||
|
||||
mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg,
|
||||
memif->data->fs_maskbit << memif->data->fs_shift,
|
||||
fs << memif->data->fs_shift);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_params);
|
||||
|
||||
int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free);
|
||||
|
||||
int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_pcm_runtime * const runtime = substream->runtime;
|
||||
struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
|
||||
struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage];
|
||||
const struct mtk_base_irq_data *irq_data = irqs->irq_data;
|
||||
unsigned int counter = runtime->period_size;
|
||||
int fs;
|
||||
|
||||
dev_dbg(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
if (memif->data->enable_shift >= 0)
|
||||
mtk_regmap_update_bits(afe->regmap,
|
||||
memif->data->enable_reg,
|
||||
1 << memif->data->enable_shift,
|
||||
1 << memif->data->enable_shift);
|
||||
|
||||
/* set irq counter */
|
||||
mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg,
|
||||
irq_data->irq_cnt_maskbit
|
||||
<< irq_data->irq_cnt_shift,
|
||||
counter << irq_data->irq_cnt_shift);
|
||||
|
||||
/* set irq fs */
|
||||
fs = afe->irq_fs(substream, runtime->rate);
|
||||
|
||||
if (fs < 0)
|
||||
return -EINVAL;
|
||||
|
||||
mtk_regmap_update_bits(afe->regmap, irq_data->irq_fs_reg,
|
||||
irq_data->irq_fs_maskbit
|
||||
<< irq_data->irq_fs_shift,
|
||||
fs << irq_data->irq_fs_shift);
|
||||
|
||||
/* enable interrupt */
|
||||
mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,
|
||||
1 << irq_data->irq_en_shift,
|
||||
1 << irq_data->irq_en_shift);
|
||||
|
||||
return 0;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,
|
||||
1 << memif->data->enable_shift, 0);
|
||||
/* disable interrupt */
|
||||
mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,
|
||||
1 << irq_data->irq_en_shift,
|
||||
0 << irq_data->irq_en_shift);
|
||||
/* and clear pending IRQ */
|
||||
mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg,
|
||||
1 << irq_data->irq_clr_shift);
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_fe_trigger);
|
||||
|
||||
int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
|
||||
int hd_audio = 0;
|
||||
|
||||
/* set hd mode */
|
||||
switch (substream->runtime->format) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
hd_audio = 0;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
hd_audio = 1;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
hd_audio = 1;
|
||||
break;
|
||||
default:
|
||||
dev_err(afe->dev, "%s() error: unsupported format %d\n",
|
||||
__func__, substream->runtime->format);
|
||||
break;
|
||||
}
|
||||
|
||||
mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg,
|
||||
1 << memif->data->hd_shift,
|
||||
hd_audio << memif->data->hd_shift);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare);
|
||||
|
||||
const struct snd_soc_dai_ops mtk_afe_fe_ops = {
|
||||
.startup = mtk_afe_fe_startup,
|
||||
.shutdown = mtk_afe_fe_shutdown,
|
||||
.hw_params = mtk_afe_fe_hw_params,
|
||||
.hw_free = mtk_afe_fe_hw_free,
|
||||
.prepare = mtk_afe_fe_prepare,
|
||||
.trigger = mtk_afe_fe_trigger,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_fe_ops);
|
||||
|
||||
static DEFINE_MUTEX(irqs_lock);
|
||||
int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe)
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&afe->irq_alloc_lock);
|
||||
for (i = 0; i < afe->irqs_size; ++i) {
|
||||
if (afe->irqs[i].irq_occupyed == 0) {
|
||||
afe->irqs[i].irq_occupyed = 1;
|
||||
mutex_unlock(&afe->irq_alloc_lock);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&afe->irq_alloc_lock);
|
||||
return afe->irqs_size;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_dynamic_irq_acquire);
|
||||
|
||||
int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id)
|
||||
{
|
||||
mutex_lock(&afe->irq_alloc_lock);
|
||||
if (irq_id >= 0 && irq_id < afe->irqs_size) {
|
||||
afe->irqs[irq_id].irq_occupyed = 0;
|
||||
mutex_unlock(&afe->irq_alloc_lock);
|
||||
return 0;
|
||||
}
|
||||
mutex_unlock(&afe->irq_alloc_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_dynamic_irq_release);
|
||||
|
||||
int mtk_afe_dai_suspend(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
|
||||
struct device *dev = afe->dev;
|
||||
struct regmap *regmap = afe->regmap;
|
||||
int i;
|
||||
|
||||
if (pm_runtime_status_suspended(dev) || afe->suspended)
|
||||
return 0;
|
||||
|
||||
if (!afe->reg_back_up)
|
||||
afe->reg_back_up =
|
||||
devm_kcalloc(dev, afe->reg_back_up_list_num,
|
||||
sizeof(unsigned int), GFP_KERNEL);
|
||||
|
||||
for (i = 0; i < afe->reg_back_up_list_num; i++)
|
||||
regmap_read(regmap, afe->reg_back_up_list[i],
|
||||
&afe->reg_back_up[i]);
|
||||
|
||||
afe->suspended = true;
|
||||
afe->runtime_suspend(dev);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_dai_suspend);
|
||||
|
||||
int mtk_afe_dai_resume(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
|
||||
struct device *dev = afe->dev;
|
||||
struct regmap *regmap = afe->regmap;
|
||||
int i = 0;
|
||||
|
||||
if (pm_runtime_status_suspended(dev) || !afe->suspended)
|
||||
return 0;
|
||||
|
||||
afe->runtime_resume(dev);
|
||||
|
||||
if (!afe->reg_back_up)
|
||||
dev_dbg(dev, "%s no reg_backup\n", __func__);
|
||||
|
||||
for (i = 0; i < afe->reg_back_up_list_num; i++)
|
||||
mtk_regmap_write(regmap, afe->reg_back_up_list[i],
|
||||
afe->reg_back_up[i]);
|
||||
|
||||
afe->suspended = false;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_dai_resume);
|
||||
|
||||
MODULE_DESCRIPTION("Mediatek simple fe dai operator");
|
||||
MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* mtk-afe-fe-dais.h -- Mediatek afe fe dai operator definition
|
||||
*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: Garlic Tseng <garlic.tseng@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.
|
||||
*/
|
||||
|
||||
#ifndef _MTK_AFE_FE_DAI_H_
|
||||
#define _MTK_AFE_FE_DAI_H_
|
||||
|
||||
struct snd_soc_dai_ops;
|
||||
struct mtk_base_afe;
|
||||
struct mtk_base_afe_memif;
|
||||
|
||||
int mtk_afe_fe_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai);
|
||||
void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai);
|
||||
int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai);
|
||||
int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai);
|
||||
int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai);
|
||||
int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai);
|
||||
|
||||
extern const struct snd_soc_dai_ops mtk_afe_fe_ops;
|
||||
|
||||
int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe);
|
||||
int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id);
|
||||
int mtk_afe_dai_suspend(struct snd_soc_dai *dai);
|
||||
int mtk_afe_dai_resume(struct snd_soc_dai *dai);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* mtk-afe-platform-driver.c -- Mediatek afe platform driver
|
||||
*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: Garlic Tseng <garlic.tseng@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/dma-mapping.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "mtk-afe-platform-driver.h"
|
||||
#include "mtk-base-afe.h"
|
||||
|
||||
static snd_pcm_uframes_t mtk_afe_pcm_pointer
|
||||
(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
|
||||
const struct mtk_base_memif_data *memif_data = memif->data;
|
||||
struct regmap *regmap = afe->regmap;
|
||||
struct device *dev = afe->dev;
|
||||
int reg_ofs_base = memif_data->reg_ofs_base;
|
||||
int reg_ofs_cur = memif_data->reg_ofs_cur;
|
||||
unsigned int hw_ptr = 0, hw_base = 0;
|
||||
int ret, pcm_ptr_bytes;
|
||||
|
||||
ret = regmap_read(regmap, reg_ofs_cur, &hw_ptr);
|
||||
if (ret || hw_ptr == 0) {
|
||||
dev_err(dev, "%s hw_ptr err\n", __func__);
|
||||
pcm_ptr_bytes = 0;
|
||||
goto POINTER_RETURN_FRAMES;
|
||||
}
|
||||
|
||||
ret = regmap_read(regmap, reg_ofs_base, &hw_base);
|
||||
if (ret || hw_base == 0) {
|
||||
dev_err(dev, "%s hw_ptr err\n", __func__);
|
||||
pcm_ptr_bytes = 0;
|
||||
goto POINTER_RETURN_FRAMES;
|
||||
}
|
||||
|
||||
pcm_ptr_bytes = hw_ptr - hw_base;
|
||||
|
||||
POINTER_RETURN_FRAMES:
|
||||
return bytes_to_frames(substream->runtime, pcm_ptr_bytes);
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops mtk_afe_pcm_ops = {
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.pointer = mtk_afe_pcm_pointer,
|
||||
};
|
||||
|
||||
static int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
size_t size;
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
|
||||
|
||||
size = afe->mtk_afe_hardware->buffer_bytes_max;
|
||||
return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
|
||||
card->dev, size, size);
|
||||
}
|
||||
|
||||
static void mtk_afe_pcm_free(struct snd_pcm *pcm)
|
||||
{
|
||||
snd_pcm_lib_preallocate_free_for_all(pcm);
|
||||
}
|
||||
|
||||
const struct snd_soc_platform_driver mtk_afe_pcm_platform = {
|
||||
.ops = &mtk_afe_pcm_ops,
|
||||
.pcm_new = mtk_afe_pcm_new,
|
||||
.pcm_free = mtk_afe_pcm_free,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform);
|
||||
|
||||
MODULE_DESCRIPTION("Mediatek simple platform driver");
|
||||
MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* mtk-afe-platform-driver.h -- Mediatek afe platform driver definition
|
||||
*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: Garlic Tseng <garlic.tseng@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.
|
||||
*/
|
||||
|
||||
#ifndef _MTK_AFE_PLATFORM_DRIVER_H_
|
||||
#define _MTK_AFE_PLATFORM_DRIVER_H_
|
||||
|
||||
extern const struct snd_soc_platform_driver mtk_afe_pcm_platform;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* mtk-base-afe.h -- Mediatek base afe structure
|
||||
*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: Garlic Tseng <garlic.tseng@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.
|
||||
*/
|
||||
|
||||
#ifndef _MTK_BASE_AFE_H_
|
||||
#define _MTK_BASE_AFE_H_
|
||||
|
||||
struct mtk_base_memif_data {
|
||||
int id;
|
||||
const char *name;
|
||||
int reg_ofs_base;
|
||||
int reg_ofs_cur;
|
||||
int fs_reg;
|
||||
int fs_shift;
|
||||
int fs_maskbit;
|
||||
int mono_reg;
|
||||
int mono_shift;
|
||||
int enable_reg;
|
||||
int enable_shift;
|
||||
int hd_reg;
|
||||
int hd_shift;
|
||||
int msb_reg;
|
||||
int msb_shift;
|
||||
int agent_disable_reg;
|
||||
int agent_disable_shift;
|
||||
};
|
||||
|
||||
struct mtk_base_irq_data {
|
||||
int id;
|
||||
int irq_cnt_reg;
|
||||
int irq_cnt_shift;
|
||||
int irq_cnt_maskbit;
|
||||
int irq_fs_reg;
|
||||
int irq_fs_shift;
|
||||
int irq_fs_maskbit;
|
||||
int irq_en_reg;
|
||||
int irq_en_shift;
|
||||
int irq_clr_reg;
|
||||
int irq_clr_shift;
|
||||
};
|
||||
|
||||
struct device;
|
||||
struct mtk_base_afe_memif;
|
||||
struct mtk_base_afe_irq;
|
||||
struct regmap;
|
||||
struct snd_pcm_substream;
|
||||
struct snd_soc_dai;
|
||||
|
||||
struct mtk_base_afe {
|
||||
void __iomem *base_addr;
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct mutex irq_alloc_lock; /* dynamic alloc irq lock */
|
||||
|
||||
unsigned int const *reg_back_up_list;
|
||||
unsigned int *reg_back_up;
|
||||
unsigned int reg_back_up_list_num;
|
||||
|
||||
int (*runtime_suspend)(struct device *dev);
|
||||
int (*runtime_resume)(struct device *dev);
|
||||
bool suspended;
|
||||
|
||||
struct mtk_base_afe_memif *memif;
|
||||
int memif_size;
|
||||
struct mtk_base_afe_irq *irqs;
|
||||
int irqs_size;
|
||||
|
||||
const struct snd_pcm_hardware *mtk_afe_hardware;
|
||||
int (*memif_fs)(struct snd_pcm_substream *substream,
|
||||
unsigned int rate);
|
||||
int (*irq_fs)(struct snd_pcm_substream *substream,
|
||||
unsigned int rate);
|
||||
|
||||
void *platform_priv;
|
||||
};
|
||||
|
||||
struct mtk_base_afe_memif {
|
||||
unsigned int phys_buf_addr;
|
||||
int buffer_size;
|
||||
struct snd_pcm_substream *substream;
|
||||
const struct mtk_base_memif_data *data;
|
||||
int irq_usage;
|
||||
int const_irq;
|
||||
};
|
||||
|
||||
struct mtk_base_afe_irq {
|
||||
const struct mtk_base_irq_data *irq_data;
|
||||
int irq_occupyed;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#
|
||||
# Copyright (C) 2015 MediaTek Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# platform driver
|
||||
snd-soc-mt2701-afe-objs := mt2701-afe-pcm.o mt2701-afe-clock-ctrl.o
|
||||
obj-$(CONFIG_SND_SOC_MT2701) += snd-soc-mt2701-afe.o
|
||||
|
||||
# machine driver
|
||||
obj-$(CONFIG_SND_SOC_MT2701_CS42448) += mt2701-cs42448.o
|
|
@ -0,0 +1,464 @@
|
|||
/*
|
||||
* mt2701-afe-clock-ctrl.c -- Mediatek 2701 afe clock ctrl
|
||||
*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: Garlic Tseng <garlic.tseng@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 <sound/soc.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "mt2701-afe-common.h"
|
||||
#include "mt2701-afe-clock-ctrl.h"
|
||||
|
||||
static const char *aud_clks[MT2701_CLOCK_NUM] = {
|
||||
[MT2701_AUD_INFRA_SYS_AUDIO] = "infra_sys_audio_clk",
|
||||
[MT2701_AUD_AUD_MUX1_SEL] = "top_audio_mux1_sel",
|
||||
[MT2701_AUD_AUD_MUX2_SEL] = "top_audio_mux2_sel",
|
||||
[MT2701_AUD_AUD_MUX1_DIV] = "top_audio_mux1_div",
|
||||
[MT2701_AUD_AUD_MUX2_DIV] = "top_audio_mux2_div",
|
||||
[MT2701_AUD_AUD_48K_TIMING] = "top_audio_48k_timing",
|
||||
[MT2701_AUD_AUD_44K_TIMING] = "top_audio_44k_timing",
|
||||
[MT2701_AUD_AUDPLL_MUX_SEL] = "top_audpll_mux_sel",
|
||||
[MT2701_AUD_APLL_SEL] = "top_apll_sel",
|
||||
[MT2701_AUD_AUD1PLL_98M] = "top_aud1_pll_98M",
|
||||
[MT2701_AUD_AUD2PLL_90M] = "top_aud2_pll_90M",
|
||||
[MT2701_AUD_HADDS2PLL_98M] = "top_hadds2_pll_98M",
|
||||
[MT2701_AUD_HADDS2PLL_294M] = "top_hadds2_pll_294M",
|
||||
[MT2701_AUD_AUDPLL] = "top_audpll",
|
||||
[MT2701_AUD_AUDPLL_D4] = "top_audpll_d4",
|
||||
[MT2701_AUD_AUDPLL_D8] = "top_audpll_d8",
|
||||
[MT2701_AUD_AUDPLL_D16] = "top_audpll_d16",
|
||||
[MT2701_AUD_AUDPLL_D24] = "top_audpll_d24",
|
||||
[MT2701_AUD_AUDINTBUS] = "top_audintbus_sel",
|
||||
[MT2701_AUD_CLK_26M] = "clk_26m",
|
||||
[MT2701_AUD_SYSPLL1_D4] = "top_syspll1_d4",
|
||||
[MT2701_AUD_AUD_K1_SRC_SEL] = "top_aud_k1_src_sel",
|
||||
[MT2701_AUD_AUD_K2_SRC_SEL] = "top_aud_k2_src_sel",
|
||||
[MT2701_AUD_AUD_K3_SRC_SEL] = "top_aud_k3_src_sel",
|
||||
[MT2701_AUD_AUD_K4_SRC_SEL] = "top_aud_k4_src_sel",
|
||||
[MT2701_AUD_AUD_K5_SRC_SEL] = "top_aud_k5_src_sel",
|
||||
[MT2701_AUD_AUD_K6_SRC_SEL] = "top_aud_k6_src_sel",
|
||||
[MT2701_AUD_AUD_K1_SRC_DIV] = "top_aud_k1_src_div",
|
||||
[MT2701_AUD_AUD_K2_SRC_DIV] = "top_aud_k2_src_div",
|
||||
[MT2701_AUD_AUD_K3_SRC_DIV] = "top_aud_k3_src_div",
|
||||
[MT2701_AUD_AUD_K4_SRC_DIV] = "top_aud_k4_src_div",
|
||||
[MT2701_AUD_AUD_K5_SRC_DIV] = "top_aud_k5_src_div",
|
||||
[MT2701_AUD_AUD_K6_SRC_DIV] = "top_aud_k6_src_div",
|
||||
[MT2701_AUD_AUD_I2S1_MCLK] = "top_aud_i2s1_mclk",
|
||||
[MT2701_AUD_AUD_I2S2_MCLK] = "top_aud_i2s2_mclk",
|
||||
[MT2701_AUD_AUD_I2S3_MCLK] = "top_aud_i2s3_mclk",
|
||||
[MT2701_AUD_AUD_I2S4_MCLK] = "top_aud_i2s4_mclk",
|
||||
[MT2701_AUD_AUD_I2S5_MCLK] = "top_aud_i2s5_mclk",
|
||||
[MT2701_AUD_AUD_I2S6_MCLK] = "top_aud_i2s6_mclk",
|
||||
[MT2701_AUD_ASM_M_SEL] = "top_asm_m_sel",
|
||||
[MT2701_AUD_ASM_H_SEL] = "top_asm_h_sel",
|
||||
[MT2701_AUD_UNIVPLL2_D4] = "top_univpll2_d4",
|
||||
[MT2701_AUD_UNIVPLL2_D2] = "top_univpll2_d2",
|
||||
[MT2701_AUD_SYSPLL_D5] = "top_syspll_d5",
|
||||
};
|
||||
|
||||
int mt2701_init_clock(struct mtk_base_afe *afe)
|
||||
{
|
||||
struct mt2701_afe_private *afe_priv = afe->platform_priv;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < MT2701_CLOCK_NUM; i++) {
|
||||
afe_priv->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]);
|
||||
if (IS_ERR(aud_clks[i])) {
|
||||
dev_warn(afe->dev, "%s devm_clk_get %s fail\n",
|
||||
__func__, aud_clks[i]);
|
||||
return PTR_ERR(aud_clks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt2701_afe_enable_clock(struct mtk_base_afe *afe)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = mt2701_turn_on_a1sys_clock(afe);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s turn_on_a1sys_clock fail %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mt2701_turn_on_a2sys_clock(afe);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s turn_on_a2sys_clock fail %d\n",
|
||||
__func__, ret);
|
||||
mt2701_turn_off_a1sys_clock(afe);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mt2701_turn_on_afe_clock(afe);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s turn_on_afe_clock fail %d\n",
|
||||
__func__, ret);
|
||||
mt2701_turn_off_a1sys_clock(afe);
|
||||
mt2701_turn_off_a2sys_clock(afe);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regmap_update_bits(afe->regmap, ASYS_TOP_CON,
|
||||
AUDIO_TOP_CON0_A1SYS_A2SYS_ON,
|
||||
AUDIO_TOP_CON0_A1SYS_A2SYS_ON);
|
||||
regmap_update_bits(afe->regmap, AFE_DAC_CON0,
|
||||
AFE_DAC_CON0_AFE_ON,
|
||||
AFE_DAC_CON0_AFE_ON);
|
||||
regmap_write(afe->regmap, PWR2_TOP_CON,
|
||||
PWR2_TOP_CON_INIT_VAL);
|
||||
regmap_write(afe->regmap, PWR1_ASM_CON1,
|
||||
PWR1_ASM_CON1_INIT_VAL);
|
||||
regmap_write(afe->regmap, PWR2_ASM_CON1,
|
||||
PWR2_ASM_CON1_INIT_VAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mt2701_afe_disable_clock(struct mtk_base_afe *afe)
|
||||
{
|
||||
mt2701_turn_off_afe_clock(afe);
|
||||
mt2701_turn_off_a1sys_clock(afe);
|
||||
mt2701_turn_off_a2sys_clock(afe);
|
||||
regmap_update_bits(afe->regmap, ASYS_TOP_CON,
|
||||
AUDIO_TOP_CON0_A1SYS_A2SYS_ON, 0);
|
||||
regmap_update_bits(afe->regmap, AFE_DAC_CON0,
|
||||
AFE_DAC_CON0_AFE_ON, 0);
|
||||
}
|
||||
|
||||
int mt2701_turn_on_a1sys_clock(struct mtk_base_afe *afe)
|
||||
{
|
||||
struct mt2701_afe_private *afe_priv = afe->platform_priv;
|
||||
int ret = 0;
|
||||
|
||||
/* Set Mux */
|
||||
ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
|
||||
__func__, aud_clks[MT2701_AUD_AUD_MUX1_SEL], ret);
|
||||
goto A1SYS_CLK_AUD_MUX1_SEL_ERR;
|
||||
}
|
||||
|
||||
ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL],
|
||||
afe_priv->clocks[MT2701_AUD_AUD1PLL_98M]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__,
|
||||
aud_clks[MT2701_AUD_AUD_MUX1_SEL],
|
||||
aud_clks[MT2701_AUD_AUD1PLL_98M], ret);
|
||||
goto A1SYS_CLK_AUD_MUX1_SEL_ERR;
|
||||
}
|
||||
|
||||
/* Set Divider */
|
||||
ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
|
||||
__func__,
|
||||
aud_clks[MT2701_AUD_AUD_MUX1_DIV],
|
||||
ret);
|
||||
goto A1SYS_CLK_AUD_MUX1_DIV_ERR;
|
||||
}
|
||||
|
||||
ret = clk_set_rate(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV],
|
||||
MT2701_AUD_AUD_MUX1_DIV_RATE);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_set_parent %s-%d fail %d\n", __func__,
|
||||
aud_clks[MT2701_AUD_AUD_MUX1_DIV],
|
||||
MT2701_AUD_AUD_MUX1_DIV_RATE, ret);
|
||||
goto A1SYS_CLK_AUD_MUX1_DIV_ERR;
|
||||
}
|
||||
|
||||
/* Enable clock gate */
|
||||
ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_48K_TIMING]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
|
||||
__func__, aud_clks[MT2701_AUD_AUD_48K_TIMING], ret);
|
||||
goto A1SYS_CLK_AUD_48K_ERR;
|
||||
}
|
||||
|
||||
/* Enable infra audio */
|
||||
ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
|
||||
__func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret);
|
||||
goto A1SYS_CLK_INFRA_ERR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
A1SYS_CLK_INFRA_ERR:
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
|
||||
A1SYS_CLK_AUD_48K_ERR:
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_48K_TIMING]);
|
||||
A1SYS_CLK_AUD_MUX1_DIV_ERR:
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV]);
|
||||
A1SYS_CLK_AUD_MUX1_SEL_ERR:
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mt2701_turn_off_a1sys_clock(struct mtk_base_afe *afe)
|
||||
{
|
||||
struct mt2701_afe_private *afe_priv = afe->platform_priv;
|
||||
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_48K_TIMING]);
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV]);
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]);
|
||||
}
|
||||
|
||||
int mt2701_turn_on_a2sys_clock(struct mtk_base_afe *afe)
|
||||
{
|
||||
struct mt2701_afe_private *afe_priv = afe->platform_priv;
|
||||
int ret = 0;
|
||||
|
||||
/* Set Mux */
|
||||
ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
|
||||
__func__, aud_clks[MT2701_AUD_AUD_MUX2_SEL], ret);
|
||||
goto A2SYS_CLK_AUD_MUX2_SEL_ERR;
|
||||
}
|
||||
|
||||
ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL],
|
||||
afe_priv->clocks[MT2701_AUD_AUD2PLL_90M]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__,
|
||||
aud_clks[MT2701_AUD_AUD_MUX2_SEL],
|
||||
aud_clks[MT2701_AUD_AUD2PLL_90M], ret);
|
||||
goto A2SYS_CLK_AUD_MUX2_SEL_ERR;
|
||||
}
|
||||
|
||||
/* Set Divider */
|
||||
ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
|
||||
__func__, aud_clks[MT2701_AUD_AUD_MUX2_DIV], ret);
|
||||
goto A2SYS_CLK_AUD_MUX2_DIV_ERR;
|
||||
}
|
||||
|
||||
ret = clk_set_rate(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV],
|
||||
MT2701_AUD_AUD_MUX2_DIV_RATE);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_set_parent %s-%d fail %d\n", __func__,
|
||||
aud_clks[MT2701_AUD_AUD_MUX2_DIV],
|
||||
MT2701_AUD_AUD_MUX2_DIV_RATE, ret);
|
||||
goto A2SYS_CLK_AUD_MUX2_DIV_ERR;
|
||||
}
|
||||
|
||||
/* Enable clock gate */
|
||||
ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_44K_TIMING]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
|
||||
__func__, aud_clks[MT2701_AUD_AUD_44K_TIMING], ret);
|
||||
goto A2SYS_CLK_AUD_44K_ERR;
|
||||
}
|
||||
|
||||
/* Enable infra audio */
|
||||
ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
|
||||
__func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret);
|
||||
goto A2SYS_CLK_INFRA_ERR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
A2SYS_CLK_INFRA_ERR:
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
|
||||
A2SYS_CLK_AUD_44K_ERR:
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_44K_TIMING]);
|
||||
A2SYS_CLK_AUD_MUX2_DIV_ERR:
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV]);
|
||||
A2SYS_CLK_AUD_MUX2_SEL_ERR:
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mt2701_turn_off_a2sys_clock(struct mtk_base_afe *afe)
|
||||
{
|
||||
struct mt2701_afe_private *afe_priv = afe->platform_priv;
|
||||
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_44K_TIMING]);
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV]);
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]);
|
||||
}
|
||||
|
||||
int mt2701_turn_on_afe_clock(struct mtk_base_afe *afe)
|
||||
{
|
||||
struct mt2701_afe_private *afe_priv = afe->platform_priv;
|
||||
int ret;
|
||||
|
||||
/* enable INFRA_SYS */
|
||||
ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
|
||||
__func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret);
|
||||
goto AFE_AUD_INFRA_ERR;
|
||||
}
|
||||
|
||||
/* Set MT2701_AUD_AUDINTBUS to MT2701_AUD_SYSPLL1_D4 */
|
||||
ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUDINTBUS]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
|
||||
__func__, aud_clks[MT2701_AUD_AUDINTBUS], ret);
|
||||
goto AFE_AUD_AUDINTBUS_ERR;
|
||||
}
|
||||
|
||||
ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_AUDINTBUS],
|
||||
afe_priv->clocks[MT2701_AUD_SYSPLL1_D4]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__,
|
||||
aud_clks[MT2701_AUD_AUDINTBUS],
|
||||
aud_clks[MT2701_AUD_SYSPLL1_D4], ret);
|
||||
goto AFE_AUD_AUDINTBUS_ERR;
|
||||
}
|
||||
|
||||
/* Set MT2701_AUD_ASM_H_SEL to MT2701_AUD_UNIVPLL2_D2 */
|
||||
ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_ASM_H_SEL]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
|
||||
__func__, aud_clks[MT2701_AUD_ASM_H_SEL], ret);
|
||||
goto AFE_AUD_ASM_H_ERR;
|
||||
}
|
||||
|
||||
ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_ASM_H_SEL],
|
||||
afe_priv->clocks[MT2701_AUD_UNIVPLL2_D2]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__,
|
||||
aud_clks[MT2701_AUD_ASM_H_SEL],
|
||||
aud_clks[MT2701_AUD_UNIVPLL2_D2], ret);
|
||||
goto AFE_AUD_ASM_H_ERR;
|
||||
}
|
||||
|
||||
/* Set MT2701_AUD_ASM_M_SEL to MT2701_AUD_UNIVPLL2_D4 */
|
||||
ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_ASM_M_SEL]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
|
||||
__func__, aud_clks[MT2701_AUD_ASM_M_SEL], ret);
|
||||
goto AFE_AUD_ASM_M_ERR;
|
||||
}
|
||||
|
||||
ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_ASM_M_SEL],
|
||||
afe_priv->clocks[MT2701_AUD_UNIVPLL2_D4]);
|
||||
if (ret) {
|
||||
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__,
|
||||
aud_clks[MT2701_AUD_ASM_M_SEL],
|
||||
aud_clks[MT2701_AUD_UNIVPLL2_D4], ret);
|
||||
goto AFE_AUD_ASM_M_ERR;
|
||||
}
|
||||
|
||||
regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
|
||||
AUDIO_TOP_CON0_PDN_AFE, 0);
|
||||
regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
|
||||
AUDIO_TOP_CON0_PDN_APLL_CK, 0);
|
||||
regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
|
||||
AUDIO_TOP_CON4_PDN_A1SYS, 0);
|
||||
regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
|
||||
AUDIO_TOP_CON4_PDN_A2SYS, 0);
|
||||
regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
|
||||
AUDIO_TOP_CON4_PDN_AFE_CONN, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
AFE_AUD_ASM_M_ERR:
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_M_SEL]);
|
||||
AFE_AUD_ASM_H_ERR:
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_H_SEL]);
|
||||
AFE_AUD_AUDINTBUS_ERR:
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUDINTBUS]);
|
||||
AFE_AUD_INFRA_ERR:
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mt2701_turn_off_afe_clock(struct mtk_base_afe *afe)
|
||||
{
|
||||
struct mt2701_afe_private *afe_priv = afe->platform_priv;
|
||||
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
|
||||
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUDINTBUS]);
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_H_SEL]);
|
||||
clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_M_SEL]);
|
||||
|
||||
regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
|
||||
AUDIO_TOP_CON0_PDN_AFE, AUDIO_TOP_CON0_PDN_AFE);
|
||||
regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
|
||||
AUDIO_TOP_CON0_PDN_APLL_CK,
|
||||
AUDIO_TOP_CON0_PDN_APLL_CK);
|
||||
regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
|
||||
AUDIO_TOP_CON4_PDN_A1SYS,
|
||||
AUDIO_TOP_CON4_PDN_A1SYS);
|
||||
regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
|
||||
AUDIO_TOP_CON4_PDN_A2SYS,
|
||||
AUDIO_TOP_CON4_PDN_A2SYS);
|
||||
regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
|
||||
AUDIO_TOP_CON4_PDN_AFE_CONN,
|
||||
AUDIO_TOP_CON4_PDN_AFE_CONN);
|
||||
}
|
||||
|
||||
void mt2701_mclk_configuration(struct mtk_base_afe *afe, int id, int domain,
|
||||
int mclk)
|
||||
{
|
||||
struct mt2701_afe_private *afe_priv = afe->platform_priv;
|
||||
int ret;
|
||||
int aud_src_div_id = MT2701_AUD_AUD_K1_SRC_DIV + id;
|
||||
int aud_src_clk_id = MT2701_AUD_AUD_K1_SRC_SEL + id;
|
||||
|
||||
/* Set MCLK Kx_SRC_SEL(domain) */
|
||||
ret = clk_prepare_enable(afe_priv->clocks[aud_src_clk_id]);
|
||||
if (ret)
|
||||
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
|
||||
__func__, aud_clks[aud_src_clk_id], ret);
|
||||
|
||||
if (domain == 0) {
|
||||
ret = clk_set_parent(afe_priv->clocks[aud_src_clk_id],
|
||||
afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]);
|
||||
if (ret)
|
||||
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
|
||||
__func__, aud_clks[aud_src_clk_id],
|
||||
aud_clks[MT2701_AUD_AUD_MUX1_SEL], ret);
|
||||
} else {
|
||||
ret = clk_set_parent(afe_priv->clocks[aud_src_clk_id],
|
||||
afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]);
|
||||
if (ret)
|
||||
dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
|
||||
__func__, aud_clks[aud_src_clk_id],
|
||||
aud_clks[MT2701_AUD_AUD_MUX2_SEL], ret);
|
||||
}
|
||||
clk_disable_unprepare(afe_priv->clocks[aud_src_clk_id]);
|
||||
|
||||
/* Set MCLK Kx_SRC_DIV(divider) */
|
||||
ret = clk_prepare_enable(afe_priv->clocks[aud_src_div_id]);
|
||||
if (ret)
|
||||
dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
|
||||
__func__, aud_clks[aud_src_div_id], ret);
|
||||
|
||||
ret = clk_set_rate(afe_priv->clocks[aud_src_div_id], mclk);
|
||||
if (ret)
|
||||
dev_err(afe->dev, "%s clk_set_rate %s-%d fail %d\n", __func__,
|
||||
aud_clks[aud_src_div_id], mclk, ret);
|
||||
clk_disable_unprepare(afe_priv->clocks[aud_src_div_id]);
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("MT2701 afe clock control");
|
||||
MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* mt2701-afe-clock-ctrl.h -- Mediatek 2701 afe clock ctrl definition
|
||||
*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: Garlic Tseng <garlic.tseng@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.
|
||||
*/
|
||||
|
||||
#ifndef _MT2701_AFE_CLOCK_CTRL_H_
|
||||
#define _MT2701_AFE_CLOCK_CTRL_H_
|
||||
|
||||
struct mtk_base_afe;
|
||||
|
||||
int mt2701_init_clock(struct mtk_base_afe *afe);
|
||||
int mt2701_afe_enable_clock(struct mtk_base_afe *afe);
|
||||
void mt2701_afe_disable_clock(struct mtk_base_afe *afe);
|
||||
|
||||
int mt2701_turn_on_a1sys_clock(struct mtk_base_afe *afe);
|
||||
void mt2701_turn_off_a1sys_clock(struct mtk_base_afe *afe);
|
||||
|
||||
int mt2701_turn_on_a2sys_clock(struct mtk_base_afe *afe);
|
||||
void mt2701_turn_off_a2sys_clock(struct mtk_base_afe *afe);
|
||||
|
||||
int mt2701_turn_on_afe_clock(struct mtk_base_afe *afe);
|
||||
void mt2701_turn_off_afe_clock(struct mtk_base_afe *afe);
|
||||
|
||||
void mt2701_mclk_configuration(struct mtk_base_afe *afe, int id, int domain,
|
||||
int mclk);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* mt2701-afe-common.h -- Mediatek 2701 audio driver definitions
|
||||
*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: Garlic Tseng <garlic.tseng@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.
|
||||
*/
|
||||
|
||||
#ifndef _MT_2701_AFE_COMMON_H_
|
||||
#define _MT_2701_AFE_COMMON_H_
|
||||
#include <sound/soc.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regmap.h>
|
||||
#include "mt2701-reg.h"
|
||||
#include "../common/mtk-base-afe.h"
|
||||
|
||||
#define MT2701_STREAM_DIR_NUM (SNDRV_PCM_STREAM_LAST + 1)
|
||||
#define MT2701_PLL_DOMAIN_0_RATE 98304000
|
||||
#define MT2701_PLL_DOMAIN_1_RATE 90316800
|
||||
#define MT2701_AUD_AUD_MUX1_DIV_RATE (MT2701_PLL_DOMAIN_0_RATE / 2)
|
||||
#define MT2701_AUD_AUD_MUX2_DIV_RATE (MT2701_PLL_DOMAIN_1_RATE / 2)
|
||||
|
||||
enum {
|
||||
MT2701_I2S_1,
|
||||
MT2701_I2S_2,
|
||||
MT2701_I2S_3,
|
||||
MT2701_I2S_4,
|
||||
MT2701_I2S_NUM,
|
||||
};
|
||||
|
||||
enum {
|
||||
MT2701_MEMIF_DL1,
|
||||
MT2701_MEMIF_DL2,
|
||||
MT2701_MEMIF_DL3,
|
||||
MT2701_MEMIF_DL4,
|
||||
MT2701_MEMIF_DL5,
|
||||
MT2701_MEMIF_DL_SINGLE_NUM,
|
||||
MT2701_MEMIF_DLM = MT2701_MEMIF_DL_SINGLE_NUM,
|
||||
MT2701_MEMIF_UL1,
|
||||
MT2701_MEMIF_UL2,
|
||||
MT2701_MEMIF_UL3,
|
||||
MT2701_MEMIF_UL4,
|
||||
MT2701_MEMIF_UL5,
|
||||
MT2701_MEMIF_DLBT,
|
||||
MT2701_MEMIF_ULBT,
|
||||
MT2701_MEMIF_NUM,
|
||||
MT2701_IO_I2S = MT2701_MEMIF_NUM,
|
||||
MT2701_IO_2ND_I2S,
|
||||
MT2701_IO_3RD_I2S,
|
||||
MT2701_IO_4TH_I2S,
|
||||
MT2701_IO_5TH_I2S,
|
||||
MT2701_IO_6TH_I2S,
|
||||
MT2701_IO_MRG,
|
||||
};
|
||||
|
||||
enum {
|
||||
MT2701_IRQ_ASYS_START,
|
||||
MT2701_IRQ_ASYS_IRQ1 = MT2701_IRQ_ASYS_START,
|
||||
MT2701_IRQ_ASYS_IRQ2,
|
||||
MT2701_IRQ_ASYS_IRQ3,
|
||||
MT2701_IRQ_ASYS_END,
|
||||
};
|
||||
|
||||
/* 2701 clock def */
|
||||
enum audio_system_clock_type {
|
||||
MT2701_AUD_INFRA_SYS_AUDIO,
|
||||
MT2701_AUD_AUD_MUX1_SEL,
|
||||
MT2701_AUD_AUD_MUX2_SEL,
|
||||
MT2701_AUD_AUD_MUX1_DIV,
|
||||
MT2701_AUD_AUD_MUX2_DIV,
|
||||
MT2701_AUD_AUD_48K_TIMING,
|
||||
MT2701_AUD_AUD_44K_TIMING,
|
||||
MT2701_AUD_AUDPLL_MUX_SEL,
|
||||
MT2701_AUD_APLL_SEL,
|
||||
MT2701_AUD_AUD1PLL_98M,
|
||||
MT2701_AUD_AUD2PLL_90M,
|
||||
MT2701_AUD_HADDS2PLL_98M,
|
||||
MT2701_AUD_HADDS2PLL_294M,
|
||||
MT2701_AUD_AUDPLL,
|
||||
MT2701_AUD_AUDPLL_D4,
|
||||
MT2701_AUD_AUDPLL_D8,
|
||||
MT2701_AUD_AUDPLL_D16,
|
||||
MT2701_AUD_AUDPLL_D24,
|
||||
MT2701_AUD_AUDINTBUS,
|
||||
MT2701_AUD_CLK_26M,
|
||||
MT2701_AUD_SYSPLL1_D4,
|
||||
MT2701_AUD_AUD_K1_SRC_SEL,
|
||||
MT2701_AUD_AUD_K2_SRC_SEL,
|
||||
MT2701_AUD_AUD_K3_SRC_SEL,
|
||||
MT2701_AUD_AUD_K4_SRC_SEL,
|
||||
MT2701_AUD_AUD_K5_SRC_SEL,
|
||||
MT2701_AUD_AUD_K6_SRC_SEL,
|
||||
MT2701_AUD_AUD_K1_SRC_DIV,
|
||||
MT2701_AUD_AUD_K2_SRC_DIV,
|
||||
MT2701_AUD_AUD_K3_SRC_DIV,
|
||||
MT2701_AUD_AUD_K4_SRC_DIV,
|
||||
MT2701_AUD_AUD_K5_SRC_DIV,
|
||||
MT2701_AUD_AUD_K6_SRC_DIV,
|
||||
MT2701_AUD_AUD_I2S1_MCLK,
|
||||
MT2701_AUD_AUD_I2S2_MCLK,
|
||||
MT2701_AUD_AUD_I2S3_MCLK,
|
||||
MT2701_AUD_AUD_I2S4_MCLK,
|
||||
MT2701_AUD_AUD_I2S5_MCLK,
|
||||
MT2701_AUD_AUD_I2S6_MCLK,
|
||||
MT2701_AUD_ASM_M_SEL,
|
||||
MT2701_AUD_ASM_H_SEL,
|
||||
MT2701_AUD_UNIVPLL2_D4,
|
||||
MT2701_AUD_UNIVPLL2_D2,
|
||||
MT2701_AUD_SYSPLL_D5,
|
||||
MT2701_CLOCK_NUM
|
||||
};
|
||||
|
||||
static const unsigned int mt2701_afe_backup_list[] = {
|
||||
AUDIO_TOP_CON0,
|
||||
AUDIO_TOP_CON4,
|
||||
AUDIO_TOP_CON5,
|
||||
ASYS_TOP_CON,
|
||||
AFE_CONN0,
|
||||
AFE_CONN1,
|
||||
AFE_CONN2,
|
||||
AFE_CONN3,
|
||||
AFE_CONN15,
|
||||
AFE_CONN16,
|
||||
AFE_CONN17,
|
||||
AFE_CONN18,
|
||||
AFE_CONN19,
|
||||
AFE_CONN20,
|
||||
AFE_CONN21,
|
||||
AFE_CONN22,
|
||||
AFE_DAC_CON0,
|
||||
AFE_MEMIF_PBUF_SIZE,
|
||||
};
|
||||
|
||||
struct snd_pcm_substream;
|
||||
struct mtk_base_irq_data;
|
||||
|
||||
struct mt2701_i2s_data {
|
||||
int i2s_ctrl_reg;
|
||||
int i2s_pwn_shift;
|
||||
int i2s_asrc_fs_shift;
|
||||
int i2s_asrc_fs_mask;
|
||||
};
|
||||
|
||||
enum mt2701_i2s_dir {
|
||||
I2S_OUT,
|
||||
I2S_IN,
|
||||
I2S_DIR_NUM,
|
||||
};
|
||||
|
||||
struct mt2701_i2s_path {
|
||||
int dai_id;
|
||||
int mclk_rate;
|
||||
int on[I2S_DIR_NUM];
|
||||
int occupied[I2S_DIR_NUM];
|
||||
const struct mt2701_i2s_data *i2s_data[2];
|
||||
};
|
||||
|
||||
struct mt2701_afe_private {
|
||||
struct clk *clocks[MT2701_CLOCK_NUM];
|
||||
struct mt2701_i2s_path i2s_path[MT2701_I2S_NUM];
|
||||
bool mrg_enable[MT2701_STREAM_DIR_NUM];
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,412 @@
|
|||
/*
|
||||
* mt2701-cs42448.c -- MT2701 CS42448 ALSA SoC machine driver
|
||||
*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: Ir Lian <ir.lian@mediatek.com>
|
||||
* Garlic Tseng <garlic.tseng@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 <sound/soc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include "mt2701-afe-common.h"
|
||||
|
||||
struct mt2701_cs42448_private {
|
||||
int i2s1_in_mux;
|
||||
int i2s1_in_mux_gpio_sel_1;
|
||||
int i2s1_in_mux_gpio_sel_2;
|
||||
};
|
||||
|
||||
static const char * const i2sin_mux_switch_text[] = {
|
||||
"ADC_SDOUT2",
|
||||
"ADC_SDOUT3",
|
||||
"I2S_IN_1",
|
||||
"I2S_IN_2",
|
||||
};
|
||||
|
||||
static const struct soc_enum i2sin_mux_enum =
|
||||
SOC_ENUM_SINGLE_EXT(4, i2sin_mux_switch_text);
|
||||
|
||||
static int mt2701_cs42448_i2sin1_mux_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
|
||||
struct mt2701_cs42448_private *priv = snd_soc_card_get_drvdata(card);
|
||||
|
||||
ucontrol->value.integer.value[0] = priv->i2s1_in_mux;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt2701_cs42448_i2sin1_mux_set(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
|
||||
struct mt2701_cs42448_private *priv = snd_soc_card_get_drvdata(card);
|
||||
|
||||
if (ucontrol->value.integer.value[0] == priv->i2s1_in_mux)
|
||||
return 0;
|
||||
|
||||
switch (ucontrol->value.integer.value[0]) {
|
||||
case 0:
|
||||
gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0);
|
||||
gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0);
|
||||
break;
|
||||
case 1:
|
||||
gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1);
|
||||
gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0);
|
||||
break;
|
||||
case 2:
|
||||
gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0);
|
||||
gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1);
|
||||
break;
|
||||
case 3:
|
||||
gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1);
|
||||
gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1);
|
||||
break;
|
||||
default:
|
||||
dev_warn(card->dev, "%s invalid setting\n", __func__);
|
||||
}
|
||||
|
||||
priv->i2s1_in_mux = ucontrol->value.integer.value[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget
|
||||
mt2701_cs42448_asoc_card_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_LINE("Line Out Jack", NULL),
|
||||
SND_SOC_DAPM_MIC("AMIC", NULL),
|
||||
SND_SOC_DAPM_LINE("Tuner In", NULL),
|
||||
SND_SOC_DAPM_LINE("Satellite Tuner In", NULL),
|
||||
SND_SOC_DAPM_LINE("AUX In", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new mt2701_cs42448_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Line Out Jack"),
|
||||
SOC_DAPM_PIN_SWITCH("AMIC"),
|
||||
SOC_DAPM_PIN_SWITCH("Tuner In"),
|
||||
SOC_DAPM_PIN_SWITCH("Satellite Tuner In"),
|
||||
SOC_DAPM_PIN_SWITCH("AUX In"),
|
||||
SOC_ENUM_EXT("I2SIN1_MUX_Switch", i2sin_mux_enum,
|
||||
mt2701_cs42448_i2sin1_mux_get,
|
||||
mt2701_cs42448_i2sin1_mux_set),
|
||||
};
|
||||
|
||||
static const unsigned int mt2701_cs42448_sampling_rates[] = {48000};
|
||||
|
||||
static struct snd_pcm_hw_constraint_list mt2701_cs42448_constraints_rates = {
|
||||
.count = ARRAY_SIZE(mt2701_cs42448_sampling_rates),
|
||||
.list = mt2701_cs42448_sampling_rates,
|
||||
.mask = 0,
|
||||
};
|
||||
|
||||
static int mt2701_cs42448_fe_ops_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = snd_pcm_hw_constraint_list(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
&mt2701_cs42448_constraints_rates);
|
||||
if (err < 0) {
|
||||
dev_err(substream->pcm->card->dev,
|
||||
"%s snd_pcm_hw_constraint_list failed: 0x%x\n",
|
||||
__func__, err);
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops mt2701_cs42448_48k_fe_ops = {
|
||||
.startup = mt2701_cs42448_fe_ops_startup,
|
||||
};
|
||||
|
||||
static int mt2701_cs42448_be_ops_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 *cpu_dai = rtd->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
unsigned int mclk_rate;
|
||||
unsigned int rate = params_rate(params);
|
||||
unsigned int div_mclk_over_bck = rate > 192000 ? 2 : 4;
|
||||
unsigned int div_bck_over_lrck = 64;
|
||||
|
||||
mclk_rate = rate * div_bck_over_lrck * div_mclk_over_bck;
|
||||
|
||||
/* mt2701 mclk */
|
||||
snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate, SND_SOC_CLOCK_OUT);
|
||||
|
||||
/* codec mclk */
|
||||
snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate, SND_SOC_CLOCK_IN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops mt2701_cs42448_be_ops = {
|
||||
.hw_params = mt2701_cs42448_be_ops_hw_params
|
||||
};
|
||||
|
||||
enum {
|
||||
DAI_LINK_FE_MULTI_CH_OUT,
|
||||
DAI_LINK_FE_PCM0_IN,
|
||||
DAI_LINK_FE_PCM1_IN,
|
||||
DAI_LINK_FE_BT_OUT,
|
||||
DAI_LINK_FE_BT_IN,
|
||||
DAI_LINK_BE_I2S0,
|
||||
DAI_LINK_BE_I2S1,
|
||||
DAI_LINK_BE_I2S2,
|
||||
DAI_LINK_BE_I2S3,
|
||||
DAI_LINK_BE_MRG_BT,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = {
|
||||
/* FE */
|
||||
[DAI_LINK_FE_MULTI_CH_OUT] = {
|
||||
.name = "mt2701-cs42448-multi-ch-out",
|
||||
.stream_name = "mt2701-cs42448-multi-ch-out",
|
||||
.cpu_dai_name = "PCM_multi",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
|
||||
SND_SOC_DPCM_TRIGGER_POST},
|
||||
.ops = &mt2701_cs42448_48k_fe_ops,
|
||||
.dynamic = 1,
|
||||
.dpcm_playback = 1,
|
||||
},
|
||||
[DAI_LINK_FE_PCM0_IN] = {
|
||||
.name = "mt2701-cs42448-pcm0",
|
||||
.stream_name = "mt2701-cs42448-pcm0-data-UL",
|
||||
.cpu_dai_name = "PCM0",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
|
||||
SND_SOC_DPCM_TRIGGER_POST},
|
||||
.ops = &mt2701_cs42448_48k_fe_ops,
|
||||
.dynamic = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
[DAI_LINK_FE_PCM1_IN] = {
|
||||
.name = "mt2701-cs42448-pcm1-data-UL",
|
||||
.stream_name = "mt2701-cs42448-pcm1-data-UL",
|
||||
.cpu_dai_name = "PCM1",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
|
||||
SND_SOC_DPCM_TRIGGER_POST},
|
||||
.ops = &mt2701_cs42448_48k_fe_ops,
|
||||
.dynamic = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
[DAI_LINK_FE_BT_OUT] = {
|
||||
.name = "mt2701-cs42448-pcm-BT-out",
|
||||
.stream_name = "mt2701-cs42448-pcm-BT",
|
||||
.cpu_dai_name = "PCM_BT_DL",
|
||||
.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_FE_BT_IN] = {
|
||||
.name = "mt2701-cs42448-pcm-BT-in",
|
||||
.stream_name = "mt2701-cs42448-pcm-BT",
|
||||
.cpu_dai_name = "PCM_BT_UL",
|
||||
.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,
|
||||
},
|
||||
/* BE */
|
||||
[DAI_LINK_BE_I2S0] = {
|
||||
.name = "mt2701-cs42448-I2S0",
|
||||
.cpu_dai_name = "I2S0",
|
||||
.no_pcm = 1,
|
||||
.codec_dai_name = "cs42448",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
|
||||
| SND_SOC_DAIFMT_GATED,
|
||||
.ops = &mt2701_cs42448_be_ops,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
[DAI_LINK_BE_I2S1] = {
|
||||
.name = "mt2701-cs42448-I2S1",
|
||||
.cpu_dai_name = "I2S1",
|
||||
.no_pcm = 1,
|
||||
.codec_dai_name = "cs42448",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
|
||||
| SND_SOC_DAIFMT_GATED,
|
||||
.ops = &mt2701_cs42448_be_ops,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
[DAI_LINK_BE_I2S2] = {
|
||||
.name = "mt2701-cs42448-I2S2",
|
||||
.cpu_dai_name = "I2S2",
|
||||
.no_pcm = 1,
|
||||
.codec_dai_name = "cs42448",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
|
||||
| SND_SOC_DAIFMT_GATED,
|
||||
.ops = &mt2701_cs42448_be_ops,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
[DAI_LINK_BE_I2S3] = {
|
||||
.name = "mt2701-cs42448-I2S3",
|
||||
.cpu_dai_name = "I2S3",
|
||||
.no_pcm = 1,
|
||||
.codec_dai_name = "cs42448",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
|
||||
| SND_SOC_DAIFMT_GATED,
|
||||
.ops = &mt2701_cs42448_be_ops,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
[DAI_LINK_BE_MRG_BT] = {
|
||||
.name = "mt2701-cs42448-MRG-BT",
|
||||
.cpu_dai_name = "MRG BT",
|
||||
.no_pcm = 1,
|
||||
.codec_dai_name = "bt-sco-pcm-wb",
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card mt2701_cs42448_soc_card = {
|
||||
.name = "mt2701-cs42448",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = mt2701_cs42448_dai_links,
|
||||
.num_links = ARRAY_SIZE(mt2701_cs42448_dai_links),
|
||||
.controls = mt2701_cs42448_controls,
|
||||
.num_controls = ARRAY_SIZE(mt2701_cs42448_controls),
|
||||
.dapm_widgets = mt2701_cs42448_asoc_card_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(mt2701_cs42448_asoc_card_dapm_widgets),
|
||||
};
|
||||
|
||||
static int mt2701_cs42448_machine_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &mt2701_cs42448_soc_card;
|
||||
int ret;
|
||||
int i;
|
||||
struct device_node *platform_node, *codec_node, *codec_node_bt_mrg;
|
||||
struct mt2701_cs42448_private *priv =
|
||||
devm_kzalloc(&pdev->dev, sizeof(struct mt2701_cs42448_private),
|
||||
GFP_KERNEL);
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
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 (mt2701_cs42448_dai_links[i].platform_name)
|
||||
continue;
|
||||
mt2701_cs42448_dai_links[i].platform_of_node = platform_node;
|
||||
}
|
||||
|
||||
card->dev = dev;
|
||||
|
||||
codec_node = of_parse_phandle(pdev->dev.of_node,
|
||||
"mediatek,audio-codec", 0);
|
||||
if (!codec_node) {
|
||||
dev_err(&pdev->dev,
|
||||
"Property 'audio-codec' missing or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
for (i = 0; i < card->num_links; i++) {
|
||||
if (mt2701_cs42448_dai_links[i].codec_name)
|
||||
continue;
|
||||
mt2701_cs42448_dai_links[i].codec_of_node = codec_node;
|
||||
}
|
||||
|
||||
codec_node_bt_mrg = of_parse_phandle(pdev->dev.of_node,
|
||||
"mediatek,audio-codec-bt-mrg", 0);
|
||||
if (!codec_node_bt_mrg) {
|
||||
dev_err(&pdev->dev,
|
||||
"Property 'audio-codec-bt-mrg' missing or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mt2701_cs42448_dai_links[DAI_LINK_BE_MRG_BT].codec_of_node
|
||||
= codec_node_bt_mrg;
|
||||
|
||||
ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->i2s1_in_mux_gpio_sel_1 =
|
||||
of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio1", 0);
|
||||
if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_1)) {
|
||||
ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_1,
|
||||
"i2s1_in_mux_gpio_sel_1");
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "%s devm_gpio_request fail %d\n",
|
||||
__func__, ret);
|
||||
gpio_direction_output(priv->i2s1_in_mux_gpio_sel_1, 0);
|
||||
}
|
||||
|
||||
priv->i2s1_in_mux_gpio_sel_2 =
|
||||
of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio2", 0);
|
||||
if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_2)) {
|
||||
ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_2,
|
||||
"i2s1_in_mux_gpio_sel_2");
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "%s devm_gpio_request fail2 %d\n",
|
||||
__func__, ret);
|
||||
gpio_direction_output(priv->i2s1_in_mux_gpio_sel_2, 0);
|
||||
}
|
||||
snd_soc_card_set_drvdata(card, priv);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id mt2701_cs42448_machine_dt_match[] = {
|
||||
{.compatible = "mediatek,mt2701-cs42448-machine",},
|
||||
{}
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_driver mt2701_cs42448_machine = {
|
||||
.driver = {
|
||||
.name = "mt2701-cs42448",
|
||||
#ifdef CONFIG_OF
|
||||
.of_match_table = mt2701_cs42448_machine_dt_match,
|
||||
#endif
|
||||
},
|
||||
.probe = mt2701_cs42448_machine_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(mt2701_cs42448_machine);
|
||||
|
||||
/* Module information */
|
||||
MODULE_DESCRIPTION("MT2701 CS42448 ALSA SoC machine driver");
|
||||
MODULE_AUTHOR("Ir Lian <ir.lian@mediatek.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("mt2701 cs42448 soc card");
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* mt2701-reg.h -- Mediatek 2701 audio driver reg definition
|
||||
*
|
||||
* Copyright (c) 2016 MediaTek Inc.
|
||||
* Author: Garlic Tseng <garlic.tseng@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.
|
||||
*/
|
||||
|
||||
#ifndef _MT2701_REG_H_
|
||||
#define _MT2701_REG_H_
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <sound/soc.h>
|
||||
#include "mt2701-afe-common.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* R E G I S T E R D E F I N I T I O N
|
||||
*****************************************************************************/
|
||||
#define AUDIO_TOP_CON0 0x0000
|
||||
#define AUDIO_TOP_CON4 0x0010
|
||||
#define AUDIO_TOP_CON5 0x0014
|
||||
#define AFE_DAIBT_CON0 0x001c
|
||||
#define AFE_MRGIF_CON 0x003c
|
||||
#define ASMI_TIMING_CON1 0x0100
|
||||
#define ASMO_TIMING_CON1 0x0104
|
||||
#define PWR1_ASM_CON1 0x0108
|
||||
#define ASYS_TOP_CON 0x0600
|
||||
#define ASYS_I2SIN1_CON 0x0604
|
||||
#define ASYS_I2SIN2_CON 0x0608
|
||||
#define ASYS_I2SIN3_CON 0x060c
|
||||
#define ASYS_I2SIN4_CON 0x0610
|
||||
#define ASYS_I2SIN5_CON 0x0614
|
||||
#define ASYS_I2SO1_CON 0x061C
|
||||
#define ASYS_I2SO2_CON 0x0620
|
||||
#define ASYS_I2SO3_CON 0x0624
|
||||
#define ASYS_I2SO4_CON 0x0628
|
||||
#define ASYS_I2SO5_CON 0x062c
|
||||
#define PWR2_TOP_CON 0x0634
|
||||
#define AFE_CONN0 0x06c0
|
||||
#define AFE_CONN1 0x06c4
|
||||
#define AFE_CONN2 0x06c8
|
||||
#define AFE_CONN3 0x06cc
|
||||
#define AFE_CONN14 0x06f8
|
||||
#define AFE_CONN15 0x06fc
|
||||
#define AFE_CONN16 0x0700
|
||||
#define AFE_CONN17 0x0704
|
||||
#define AFE_CONN18 0x0708
|
||||
#define AFE_CONN19 0x070c
|
||||
#define AFE_CONN20 0x0710
|
||||
#define AFE_CONN21 0x0714
|
||||
#define AFE_CONN22 0x0718
|
||||
#define AFE_CONN23 0x071c
|
||||
#define AFE_CONN24 0x0720
|
||||
#define AFE_CONN41 0x0764
|
||||
#define ASYS_IRQ1_CON 0x0780
|
||||
#define ASYS_IRQ2_CON 0x0784
|
||||
#define ASYS_IRQ3_CON 0x0788
|
||||
#define ASYS_IRQ_CLR 0x07c0
|
||||
#define ASYS_IRQ_STATUS 0x07c4
|
||||
#define PWR2_ASM_CON1 0x1070
|
||||
#define AFE_DAC_CON0 0x1200
|
||||
#define AFE_DAC_CON1 0x1204
|
||||
#define AFE_DAC_CON2 0x1208
|
||||
#define AFE_DAC_CON3 0x120c
|
||||
#define AFE_DAC_CON4 0x1210
|
||||
#define AFE_MEMIF_HD_CON1 0x121c
|
||||
#define AFE_MEMIF_PBUF_SIZE 0x1238
|
||||
#define AFE_MEMIF_HD_CON0 0x123c
|
||||
#define AFE_DL1_BASE 0x1240
|
||||
#define AFE_DL1_CUR 0x1244
|
||||
#define AFE_DL2_BASE 0x1250
|
||||
#define AFE_DL2_CUR 0x1254
|
||||
#define AFE_DL3_BASE 0x1260
|
||||
#define AFE_DL3_CUR 0x1264
|
||||
#define AFE_DL4_BASE 0x1270
|
||||
#define AFE_DL4_CUR 0x1274
|
||||
#define AFE_DL5_BASE 0x1280
|
||||
#define AFE_DL5_CUR 0x1284
|
||||
#define AFE_DLMCH_BASE 0x12a0
|
||||
#define AFE_DLMCH_CUR 0x12a4
|
||||
#define AFE_ARB1_BASE 0x12b0
|
||||
#define AFE_ARB1_CUR 0x12b4
|
||||
#define AFE_VUL_BASE 0x1300
|
||||
#define AFE_VUL_CUR 0x130c
|
||||
#define AFE_UL2_BASE 0x1310
|
||||
#define AFE_UL2_END 0x1318
|
||||
#define AFE_UL2_CUR 0x131c
|
||||
#define AFE_UL3_BASE 0x1320
|
||||
#define AFE_UL3_END 0x1328
|
||||
#define AFE_UL3_CUR 0x132c
|
||||
#define AFE_UL4_BASE 0x1330
|
||||
#define AFE_UL4_END 0x1338
|
||||
#define AFE_UL4_CUR 0x133c
|
||||
#define AFE_UL5_BASE 0x1340
|
||||
#define AFE_UL5_END 0x1348
|
||||
#define AFE_UL5_CUR 0x134c
|
||||
#define AFE_DAI_BASE 0x1370
|
||||
#define AFE_DAI_CUR 0x137c
|
||||
|
||||
/* AUDIO_TOP_CON0 (0x0000) */
|
||||
#define AUDIO_TOP_CON0_A1SYS_A2SYS_ON (0x3 << 0)
|
||||
#define AUDIO_TOP_CON0_PDN_AFE (0x1 << 2)
|
||||
#define AUDIO_TOP_CON0_PDN_APLL_CK (0x1 << 23)
|
||||
|
||||
/* AUDIO_TOP_CON4 (0x0010) */
|
||||
#define AUDIO_TOP_CON4_I2SO1_PWN (0x1 << 6)
|
||||
#define AUDIO_TOP_CON4_PDN_A1SYS (0x1 << 21)
|
||||
#define AUDIO_TOP_CON4_PDN_A2SYS (0x1 << 22)
|
||||
#define AUDIO_TOP_CON4_PDN_AFE_CONN (0x1 << 23)
|
||||
#define AUDIO_TOP_CON4_PDN_MRGIF (0x1 << 25)
|
||||
|
||||
/* AFE_DAIBT_CON0 (0x001c) */
|
||||
#define AFE_DAIBT_CON0_DAIBT_EN (0x1 << 0)
|
||||
#define AFE_DAIBT_CON0_BT_FUNC_EN (0x1 << 1)
|
||||
#define AFE_DAIBT_CON0_BT_FUNC_RDY (0x1 << 3)
|
||||
#define AFE_DAIBT_CON0_BT_WIDE_MODE_EN (0x1 << 9)
|
||||
#define AFE_DAIBT_CON0_MRG_USE (0x1 << 12)
|
||||
|
||||
/* PWR1_ASM_CON1 (0x0108) */
|
||||
#define PWR1_ASM_CON1_INIT_VAL (0x492)
|
||||
|
||||
/* AFE_MRGIF_CON (0x003c) */
|
||||
#define AFE_MRGIF_CON_MRG_EN (0x1 << 0)
|
||||
#define AFE_MRGIF_CON_MRG_I2S_EN (0x1 << 16)
|
||||
#define AFE_MRGIF_CON_I2S_MODE_MASK (0xf << 20)
|
||||
#define AFE_MRGIF_CON_I2S_MODE_32K (0x4 << 20)
|
||||
|
||||
/* ASYS_I2SO1_CON (0x061c) */
|
||||
#define ASYS_I2SO1_CON_FS (0x1f << 8)
|
||||
#define ASYS_I2SO1_CON_FS_SET(x) ((x) << 8)
|
||||
#define ASYS_I2SO1_CON_MULTI_CH (0x1 << 16)
|
||||
#define ASYS_I2SO1_CON_SIDEGEN (0x1 << 30)
|
||||
#define ASYS_I2SO1_CON_I2S_EN (0x1 << 0)
|
||||
/* 0:EIAJ 1:I2S */
|
||||
#define ASYS_I2SO1_CON_I2S_MODE (0x1 << 3)
|
||||
#define ASYS_I2SO1_CON_WIDE_MODE (0x1 << 1)
|
||||
#define ASYS_I2SO1_CON_WIDE_MODE_SET(x) ((x) << 1)
|
||||
|
||||
/* PWR2_TOP_CON (0x0634) */
|
||||
#define PWR2_TOP_CON_INIT_VAL (0xffe1ffff)
|
||||
|
||||
/* ASYS_IRQ_CLR (0x07c0) */
|
||||
#define ASYS_IRQ_CLR_ALL (0xffffffff)
|
||||
|
||||
/* PWR2_ASM_CON1 (0x1070) */
|
||||
#define PWR2_ASM_CON1_INIT_VAL (0x492492)
|
||||
|
||||
/* AFE_DAC_CON0 (0x1200) */
|
||||
#define AFE_DAC_CON0_AFE_ON (0x1 << 0)
|
||||
|
||||
/* AFE_MEMIF_PBUF_SIZE (0x1238) */
|
||||
#define AFE_MEMIF_PBUF_SIZE_DLM_MASK (0x1 << 29)
|
||||
#define AFE_MEMIF_PBUF_SIZE_PAIR_INTERLEAVE (0x0 << 29)
|
||||
#define AFE_MEMIF_PBUF_SIZE_FULL_INTERLEAVE (0x1 << 29)
|
||||
#define DLMCH_BIT_WIDTH_MASK (0x1 << 28)
|
||||
#define AFE_MEMIF_PBUF_SIZE_DLM_CH_MASK (0xf << 24)
|
||||
#define AFE_MEMIF_PBUF_SIZE_DLM_CH(x) ((x) << 24)
|
||||
#define AFE_MEMIF_PBUF_SIZE_DLM_BYTE_MASK (0x3 << 12)
|
||||
#define AFE_MEMIF_PBUF_SIZE_DLM_32BYTES (0x1 << 12)
|
||||
|
||||
/* I2S in/out register bit control */
|
||||
#define ASYS_I2S_CON_FS (0x1f << 8)
|
||||
#define ASYS_I2S_CON_FS_SET(x) ((x) << 8)
|
||||
#define ASYS_I2S_CON_RESET (0x1 << 30)
|
||||
#define ASYS_I2S_CON_I2S_EN (0x1 << 0)
|
||||
#define ASYS_I2S_CON_I2S_COUPLE_MODE (0x1 << 17)
|
||||
/* 0:EIAJ 1:I2S */
|
||||
#define ASYS_I2S_CON_I2S_MODE (0x1 << 3)
|
||||
#define ASYS_I2S_CON_WIDE_MODE (0x1 << 1)
|
||||
#define ASYS_I2S_CON_WIDE_MODE_SET(x) ((x) << 1)
|
||||
#define ASYS_I2S_IN_PHASE_FIX (0x1 << 31)
|
||||
|
||||
#define AFE_END_ADDR 0x15e0
|
||||
#endif
|
|
@ -0,0 +1,7 @@
|
|||
# MTK Platform Support
|
||||
obj-$(CONFIG_SND_SOC_MT8173) += mt8173-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
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* mt8173_afe_common.h -- Mediatek 8173 audio driver common definitions
|
||||
*
|
||||
* Copyright (c) 2015 MediaTek Inc.
|
||||
* Author: Koro Chen <koro.chen@mediatek.com>
|
||||
* Sascha Hauer <s.hauer@pengutronix.de>
|
||||
* Hidalgo Huang <hidalgo.huang@mediatek.com>
|
||||
* Ir Lian <ir.lian@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.
|
||||
*/
|
||||
|
||||
#ifndef _MT8173_AFE_COMMON_H_
|
||||
#define _MT8173_AFE_COMMON_H_
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
enum {
|
||||
MT8173_AFE_MEMIF_DL1,
|
||||
MT8173_AFE_MEMIF_DL2,
|
||||
MT8173_AFE_MEMIF_VUL,
|
||||
MT8173_AFE_MEMIF_DAI,
|
||||
MT8173_AFE_MEMIF_AWB,
|
||||
MT8173_AFE_MEMIF_MOD_DAI,
|
||||
MT8173_AFE_MEMIF_HDMI,
|
||||
MT8173_AFE_MEMIF_NUM,
|
||||
MT8173_AFE_IO_MOD_PCM1 = MT8173_AFE_MEMIF_NUM,
|
||||
MT8173_AFE_IO_MOD_PCM2,
|
||||
MT8173_AFE_IO_PMIC,
|
||||
MT8173_AFE_IO_I2S,
|
||||
MT8173_AFE_IO_2ND_I2S,
|
||||
MT8173_AFE_IO_HW_GAIN1,
|
||||
MT8173_AFE_IO_HW_GAIN2,
|
||||
MT8173_AFE_IO_MRG_O,
|
||||
MT8173_AFE_IO_MRG_I,
|
||||
MT8173_AFE_IO_DAIBT,
|
||||
MT8173_AFE_IO_HDMI,
|
||||
};
|
||||
|
||||
enum {
|
||||
MT8173_AFE_IRQ_DL1,
|
||||
MT8173_AFE_IRQ_DL2,
|
||||
MT8173_AFE_IRQ_VUL,
|
||||
MT8173_AFE_IRQ_DAI,
|
||||
MT8173_AFE_IRQ_AWB,
|
||||
MT8173_AFE_IRQ_MOD_DAI,
|
||||
MT8173_AFE_IRQ_HDMI,
|
||||
MT8173_AFE_IRQ_NUM,
|
||||
};
|
||||
|
||||
enum {
|
||||
MT8173_CLK_INFRASYS_AUD,
|
||||
MT8173_CLK_TOP_PDN_AUD,
|
||||
MT8173_CLK_TOP_PDN_AUD_BUS,
|
||||
MT8173_CLK_I2S0_M,
|
||||
MT8173_CLK_I2S1_M,
|
||||
MT8173_CLK_I2S2_M,
|
||||
MT8173_CLK_I2S3_M,
|
||||
MT8173_CLK_I2S3_B,
|
||||
MT8173_CLK_BCK0,
|
||||
MT8173_CLK_BCK1,
|
||||
MT8173_CLK_NUM
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -18,7 +18,7 @@
|
|||
#include <sound/soc.h>
|
||||
#include <sound/jack.h>
|
||||
#include <linux/gpio.h>
|
||||
#include "../codecs/max98090.h"
|
||||
#include "../../codecs/max98090.h"
|
||||
|
||||
static struct snd_soc_jack mt8173_max98090_jack;
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
#include <linux/of_gpio.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/jack.h>
|
||||
#include "../codecs/rt5645.h"
|
||||
#include "../../codecs/rt5645.h"
|
||||
|
||||
#define MCLK_FOR_CODECS 12288000
|
||||
|
|
@ -19,8 +19,8 @@
|
|||
#include <linux/of_gpio.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/jack.h>
|
||||
#include "../codecs/rt5645.h"
|
||||
#include "../codecs/rt5677.h"
|
||||
#include "../../codecs/rt5645.h"
|
||||
#include "../../codecs/rt5677.h"
|
||||
|
||||
#define MCLK_FOR_CODECS 12288000
|
||||
|
|
@ -19,10 +19,24 @@
|
|||
#include <linux/of_gpio.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/jack.h>
|
||||
#include "../codecs/rt5645.h"
|
||||
#include "../../codecs/rt5645.h"
|
||||
|
||||
#define MCLK_FOR_CODECS 12288000
|
||||
|
||||
enum mt8173_rt5650_mclk {
|
||||
MT8173_RT5650_MCLK_EXTERNAL = 0,
|
||||
MT8173_RT5650_MCLK_INTERNAL,
|
||||
};
|
||||
|
||||
struct mt8173_rt5650_platform_data {
|
||||
enum mt8173_rt5650_mclk pll_from;
|
||||
/* 0 = external oscillator; 1 = internal source from mt8173 */
|
||||
};
|
||||
|
||||
static struct mt8173_rt5650_platform_data mt8173_rt5650_priv = {
|
||||
.pll_from = MT8173_RT5650_MCLK_EXTERNAL,
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget mt8173_rt5650_widgets[] = {
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
SND_SOC_DAPM_MIC("Int Mic", NULL),
|
||||
|
@ -54,13 +68,29 @@ 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;
|
||||
unsigned int mclk_clock;
|
||||
int i, ret;
|
||||
|
||||
switch (mt8173_rt5650_priv.pll_from) {
|
||||
case MT8173_RT5650_MCLK_EXTERNAL:
|
||||
/* mclk = 12.288M */
|
||||
mclk_clock = MCLK_FOR_CODECS;
|
||||
break;
|
||||
case MT8173_RT5650_MCLK_INTERNAL:
|
||||
/* mclk = sampling rate*256 */
|
||||
mclk_clock = params_rate(params) * 256;
|
||||
break;
|
||||
default:
|
||||
/* mclk = 12.288M */
|
||||
mclk_clock = MCLK_FOR_CODECS;
|
||||
break;
|
||||
}
|
||||
|
||||
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,
|
||||
/* pll from mclk */
|
||||
ret = snd_soc_dai_set_pll(codec_dai, 0, 0, mclk_clock,
|
||||
params_rate(params) * 512);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -139,7 +169,9 @@ static struct snd_soc_dai_link_component mt8173_rt5650_codecs[] = {
|
|||
enum {
|
||||
DAI_LINK_PLAYBACK,
|
||||
DAI_LINK_CAPTURE,
|
||||
DAI_LINK_HDMI,
|
||||
DAI_LINK_CODEC_I2S,
|
||||
DAI_LINK_HDMI_I2S,
|
||||
};
|
||||
|
||||
/* Digital audio interface glue - connects codec <---> CPU */
|
||||
|
@ -165,6 +197,16 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = {
|
|||
.dynamic = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
[DAI_LINK_HDMI] = {
|
||||
.name = "HDMI",
|
||||
.stream_name = "HDMI PCM",
|
||||
.cpu_dai_name = "HDMI",
|
||||
.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,
|
||||
},
|
||||
/* Back End DAI links */
|
||||
[DAI_LINK_CODEC_I2S] = {
|
||||
.name = "Codec",
|
||||
|
@ -180,6 +222,13 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = {
|
|||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
[DAI_LINK_HDMI_I2S] = {
|
||||
.name = "HDMI BE",
|
||||
.cpu_dai_name = "HDMIO",
|
||||
.no_pcm = 1,
|
||||
.codec_dai_name = "i2s-hifi",
|
||||
.dpcm_playback = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card mt8173_rt5650_card = {
|
||||
|
@ -243,6 +292,24 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
|
|||
mt8173_rt5650_codecs[1].dai_name = codec_capture_dai;
|
||||
}
|
||||
|
||||
if (device_property_present(&pdev->dev, "mediatek,mclk")) {
|
||||
ret = device_property_read_u32(&pdev->dev,
|
||||
"mediatek,mclk",
|
||||
&mt8173_rt5650_priv.pll_from);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"%s snd_soc_register_card fail %d\n",
|
||||
__func__, ret);
|
||||
}
|
||||
}
|
||||
|
||||
mt8173_rt5650_dais[DAI_LINK_HDMI_I2S].codec_of_node =
|
||||
of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);
|
||||
if (!mt8173_rt5650_dais[DAI_LINK_HDMI_I2S].codec_of_node) {
|
||||
dev_err(&pdev->dev,
|
||||
"Property 'audio-codec' missing or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
card->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, card);
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
* mtk_afe_common.h -- Mediatek audio driver common definitions
|
||||
*
|
||||
* Copyright (c) 2015 MediaTek Inc.
|
||||
* Author: Koro Chen <koro.chen@mediatek.com>
|
||||
* Sascha Hauer <s.hauer@pengutronix.de>
|
||||
* Hidalgo Huang <hidalgo.huang@mediatek.com>
|
||||
* Ir Lian <ir.lian@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.
|
||||
*/
|
||||
|
||||
#ifndef _MTK_AFE_COMMON_H_
|
||||
#define _MTK_AFE_COMMON_H_
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
enum {
|
||||
MTK_AFE_MEMIF_DL1,
|
||||
MTK_AFE_MEMIF_DL2,
|
||||
MTK_AFE_MEMIF_VUL,
|
||||
MTK_AFE_MEMIF_DAI,
|
||||
MTK_AFE_MEMIF_AWB,
|
||||
MTK_AFE_MEMIF_MOD_DAI,
|
||||
MTK_AFE_MEMIF_HDMI,
|
||||
MTK_AFE_MEMIF_NUM,
|
||||
MTK_AFE_IO_MOD_PCM1 = MTK_AFE_MEMIF_NUM,
|
||||
MTK_AFE_IO_MOD_PCM2,
|
||||
MTK_AFE_IO_PMIC,
|
||||
MTK_AFE_IO_I2S,
|
||||
MTK_AFE_IO_2ND_I2S,
|
||||
MTK_AFE_IO_HW_GAIN1,
|
||||
MTK_AFE_IO_HW_GAIN2,
|
||||
MTK_AFE_IO_MRG_O,
|
||||
MTK_AFE_IO_MRG_I,
|
||||
MTK_AFE_IO_DAIBT,
|
||||
MTK_AFE_IO_HDMI,
|
||||
};
|
||||
|
||||
enum {
|
||||
MTK_AFE_IRQ_1,
|
||||
MTK_AFE_IRQ_2,
|
||||
MTK_AFE_IRQ_3,
|
||||
MTK_AFE_IRQ_4,
|
||||
MTK_AFE_IRQ_5,
|
||||
MTK_AFE_IRQ_6,
|
||||
MTK_AFE_IRQ_7,
|
||||
MTK_AFE_IRQ_8,
|
||||
MTK_AFE_IRQ_NUM,
|
||||
};
|
||||
|
||||
enum {
|
||||
MTK_CLK_INFRASYS_AUD,
|
||||
MTK_CLK_TOP_PDN_AUD,
|
||||
MTK_CLK_TOP_PDN_AUD_BUS,
|
||||
MTK_CLK_I2S0_M,
|
||||
MTK_CLK_I2S1_M,
|
||||
MTK_CLK_I2S2_M,
|
||||
MTK_CLK_I2S3_M,
|
||||
MTK_CLK_I2S3_B,
|
||||
MTK_CLK_BCK0,
|
||||
MTK_CLK_BCK1,
|
||||
MTK_CLK_NUM
|
||||
};
|
||||
|
||||
struct mtk_afe;
|
||||
struct snd_pcm_substream;
|
||||
|
||||
struct mtk_afe_memif_data {
|
||||
int id;
|
||||
const char *name;
|
||||
int reg_ofs_base;
|
||||
int reg_ofs_cur;
|
||||
int fs_shift;
|
||||
int mono_shift;
|
||||
int enable_shift;
|
||||
int irq_reg_cnt;
|
||||
int irq_cnt_shift;
|
||||
int irq_en_shift;
|
||||
int irq_fs_shift;
|
||||
int irq_clr_shift;
|
||||
int msb_shift;
|
||||
};
|
||||
|
||||
struct mtk_afe_memif {
|
||||
unsigned int phys_buf_addr;
|
||||
int buffer_size;
|
||||
struct snd_pcm_substream *substream;
|
||||
const struct mtk_afe_memif_data *data;
|
||||
const struct mtk_afe_irq_data *irqdata;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue