Commit 4c908776 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/rt5645', 'asoc/topic/rt5670',...

Merge remote-tracking branches 'asoc/topic/rt5645', 'asoc/topic/rt5670', 'asoc/topic/rt5677', 'asoc/topic/samsung' and 'asoc/topic/sgtl5000' into asoc-next
Audio Binding for Arndale boards
Required properties:
- compatible : Can be the following,
"samsung,arndale-rt5631"
- samsung,audio-cpu: The phandle of the Samsung I2S controller
- samsung,audio-codec: The phandle of the audio codec
Optional:
- samsung,model: The name of the sound-card
Arndale Boards has many audio daughter cards, one of them is
rt5631/alc5631. Below example shows audio bindings for rt5631/
alc5631 based codec.
Example:
sound {
compatible = "samsung,arndale-rt5631";
samsung,audio-cpu = <&i2s0>
samsung,audio-codec = <&rt5631>;
};
......@@ -27,6 +27,21 @@ Optional properties:
Boolean. Indicate MIC1/2 input and LOUT1/2/3 outputs are differential,
rather than single-ended.
- realtek,gpio-config
Array of six 8bit elements that configures GPIO.
0 - floating (reset value)
1 - pull down
2 - pull up
- realtek,jd1-gpio
Configures GPIO Mic Jack detection 1.
Select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively.
- realtek,jd2-gpio
- realtek,jd3-gpio
Configures GPIO Mic Jack detection 2 and 3.
Select 0 ~ 3 as OFF, GPIO4, GPIO5 and GPIO6 respectively.
Pins on the device (for linking into audio routes):
* IN1P
......@@ -56,4 +71,6 @@ rt5677 {
realtek,pow-ldo2-gpio =
<&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
realtek,in1-differential = "true";
realtek,gpio-config = /bits/ 8 <0 0 0 0 0 2>; /* pull up GPIO6 */
realtek,jd2-gpio = <3>; /* Enables Jack detection for GPIO6 */
};
......@@ -6,10 +6,17 @@ Required SoC Specific Properties:
- samsung,s3c6410-i2s: for 8/16/24bit stereo I2S.
- samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with
secondary fifo, s/w reset control and internal mux for root clk src.
- samsung,exynos5420-i2s: for 8/16/24bit multichannel(7.1) I2S with
secondary fifo, s/w reset control, internal mux for root clk src and
TDM support. TDM (Time division multiplexing) is to allow transfer of
multiple channel audio data on single data line.
- samsung,exynos5420-i2s: for 8/16/24bit multichannel(5.1) I2S for
playback, sterio channel capture, secondary fifo using internal
or external dma, s/w reset control, internal mux for root clk src
and 7.1 channel TDM support for playback. TDM (Time division multiplexing)
is to allow transfer of multiple channel audio data on single data line.
- samsung,exynos7-i2s: with all the available features of exynos5 i2s,
exynos7 I2S has 7.1 channel TDM support for capture, secondary fifo
with only external dma and more no.of root clk sampling frequencies.
- samsung,exynos7-i2s1: I2S1 on previous samsung platforms supports
stereo channels. exynos7 i2s1 upgraded to 5.1 multichannel with
slightly modified bit offsets.
- reg: physical base address of the controller and length of memory mapped
region.
......
......@@ -7,6 +7,17 @@ Required properties:
- clocks : the clock provider of SYS_MCLK
- micbias-resistor-k-ohms : the bias resistor to be used in kOmhs
The resistor can take values of 2k, 4k or 8k.
If set to 0 it will be off.
If this node is not mentioned or if the value is unknown, then
micbias resistor is set to 4K.
- micbias-voltage-m-volts : the bias voltage to be used in mVolts
The voltage can take values from 1.25V to 3V by 250mV steps
If this node is not mentionned or the value is unknown, then
the value is set to 1.25V.
- VDDA-supply : the regulator provider of VDDA
- VDDIO-supply: the regulator provider of VDDIO
......@@ -21,6 +32,8 @@ codec: sgtl5000@0a {
compatible = "fsl,sgtl5000";
reg = <0x0a>;
clocks = <&clks 150>;
micbias-resistor-k-ohms = <2>;
micbias-voltage-m-volts = <2250>;
VDDA-supply = <&reg_3p3v>;
VDDIO-supply = <&reg_3p3v>;
};
......@@ -27,6 +27,7 @@ struct samsung_i2s {
#define QUIRK_NO_MUXPSR (1 << 2)
#define QUIRK_NEED_RSTCLR (1 << 3)
#define QUIRK_SUPPORTS_TDM (1 << 4)
#define QUIRK_SUPPORTS_IDMA (1 << 5)
/* Quirks of the I2S controller */
u32 quirks;
dma_addr_t idma_addr;
......
......@@ -23,6 +23,10 @@ struct rt5645_platform_data {
unsigned int hp_det_gpio;
bool gpio_hp_det_active_high;
/* true if codec's jd function is used */
bool en_jd_func;
unsigned int jd_mode;
};
#endif
......@@ -27,6 +27,16 @@ struct rt5677_platform_data {
bool lout3_diff;
/* DMIC2 clock source selection */
enum rt5677_dmic2_clk dmic2_clk_pin;
/* configures GPIO, 0 - floating, 1 - pulldown, 2 - pullup */
u8 gpio_config[6];
/* jd1 can select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively */
unsigned int jd1_gpio;
/* jd2 and jd3 can select 0 ~ 3 as
OFF, GPIO4, GPIO5 and GPIO6 respectively */
unsigned int jd2_gpio;
unsigned int jd3_gpio;
};
#endif
......@@ -86,7 +86,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_RT5645 if I2C
select SND_SOC_RT5651 if I2C
select SND_SOC_RT5670 if I2C
select SND_SOC_RT5677 if I2C
select SND_SOC_RT5677 if I2C && SPI_MASTER
select SND_SOC_SGTL5000 if I2C
select SND_SOC_SI476X if MFD_SI476X_CORE
select SND_SOC_SIRF_AUDIO_CODEC
......@@ -519,6 +519,10 @@ config SND_SOC_RT5670
config SND_SOC_RT5677
tristate
config SND_SOC_RT5677_SPI
tristate
default SND_SOC_RT5677
#Freescale sgtl5000 codec
config SND_SOC_SGTL5000
tristate "Freescale SGTL5000 CODEC"
......
......@@ -82,6 +82,7 @@ snd-soc-rt5645-objs := rt5645.o
snd-soc-rt5651-objs := rt5651.o
snd-soc-rt5670-objs := rt5670.o
snd-soc-rt5677-objs := rt5677.o
snd-soc-rt5677-spi-objs := rt5677-spi.o
snd-soc-sgtl5000-objs := sgtl5000.o
snd-soc-alc5623-objs := alc5623.o
snd-soc-alc5632-objs := alc5632.o
......@@ -260,6 +261,7 @@ obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o
obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o
obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o
obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o
obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o
......
......@@ -554,6 +554,53 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
return 0;
}
static int is_using_asrc(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
unsigned int reg, shift, val;
switch (source->shift) {
case 0:
reg = RT5645_ASRC_3;
shift = 0;
break;
case 1:
reg = RT5645_ASRC_3;
shift = 4;
break;
case 3:
reg = RT5645_ASRC_2;
shift = 0;
break;
case 8:
reg = RT5645_ASRC_2;
shift = 4;
break;
case 9:
reg = RT5645_ASRC_2;
shift = 8;
break;
case 10:
reg = RT5645_ASRC_2;
shift = 12;
break;
default:
return 0;
}
val = (snd_soc_read(source->codec, reg) >> shift) & 0xf;
switch (val) {
case 1:
case 2:
case 3:
case 4:
return 1;
default:
return 0;
}
}
/* Digital Mixer */
static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = {
SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER,
......@@ -1246,6 +1293,30 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5645_PWR_VOL,
RT5645_PWR_MIC_DET_BIT, 0, NULL, 0),
/* ASRC */
SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5645_ASRC_1,
11, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5645_ASRC_1,
12, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5645_ASRC_1,
10, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DAC MONO L ASRC", 1, RT5645_ASRC_1,
9, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5645_ASRC_1,
8, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5645_ASRC_1,
7, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5645_ASRC_1,
5, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5645_ASRC_1,
4, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5645_ASRC_1,
3, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5645_ASRC_1,
1, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5645_ASRC_1,
0, 0, NULL, 0),
/* Input Side */
/* micbias */
SND_SOC_DAPM_MICBIAS("micbias1", RT5645_PWR_ANLG2,
......@@ -1504,6 +1575,17 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
};
static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
{ "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc },
{ "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc },
{ "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc },
{ "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc },
{ "dac mono left filter", NULL, "DAC MONO L ASRC", is_using_asrc },
{ "dac mono right filter", NULL, "DAC MONO R ASRC", is_using_asrc },
{ "dac stereo1 filter", NULL, "DAC STO ASRC", is_using_asrc },
{ "I2S1", NULL, "I2S1 ASRC" },
{ "I2S2", NULL, "I2S2 ASRC" },
{ "IN1P", NULL, "LDO2" },
{ "IN2P", NULL, "LDO2" },
......@@ -1550,12 +1632,15 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
{ "Stereo1 DMIC Mux", "DMIC1", "DMIC1" },
{ "Stereo1 DMIC Mux", "DMIC2", "DMIC2" },
{ "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC" },
{ "Mono DMIC L Mux", "DMIC1", "DMIC L1" },
{ "Mono DMIC L Mux", "DMIC2", "DMIC L2" },
{ "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC" },
{ "Mono DMIC R Mux", "DMIC1", "DMIC R1" },
{ "Mono DMIC R Mux", "DMIC2", "DMIC R2" },
{ "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC" },
{ "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" },
{ "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" },
......@@ -2029,8 +2114,11 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
struct snd_soc_codec *codec = dai->codec;
unsigned int val = 0;
if (rx_mask || tx_mask)
if (rx_mask || tx_mask) {
val |= (1 << 14);
snd_soc_update_bits(codec, RT5645_BASS_BACK,
RT5645_G_BB_BST_MASK, RT5645_G_BB_BST_25DB);
}
switch (slots) {
case 4:
......@@ -2071,8 +2159,8 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
switch (level) {
case SND_SOC_BIAS_STANDBY:
if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
case SND_SOC_BIAS_PREPARE:
if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
RT5645_PWR_VREF1 | RT5645_PWR_MB |
RT5645_PWR_BG | RT5645_PWR_VREF2,
......@@ -2087,15 +2175,24 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
}
break;
case SND_SOC_BIAS_STANDBY:
snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
RT5645_PWR_VREF1 | RT5645_PWR_MB |
RT5645_PWR_BG | RT5645_PWR_VREF2,
RT5645_PWR_VREF1 | RT5645_PWR_MB |
RT5645_PWR_BG | RT5645_PWR_VREF2);
snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
RT5645_PWR_FV1 | RT5645_PWR_FV2,
RT5645_PWR_FV1 | RT5645_PWR_FV2);
break;
case SND_SOC_BIAS_OFF:
snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100);
snd_soc_write(codec, RT5645_GEN_CTRL1, 0x0128);
snd_soc_write(codec, RT5645_PWR_DIG1, 0x0000);
snd_soc_write(codec, RT5645_PWR_DIG2, 0x0000);
snd_soc_write(codec, RT5645_PWR_VOL, 0x0000);
snd_soc_write(codec, RT5645_PWR_MIXER, 0x0000);
snd_soc_write(codec, RT5645_PWR_ANLG1, 0x0000);
snd_soc_write(codec, RT5645_PWR_ANLG2, 0x0000);
snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
RT5645_PWR_VREF1 | RT5645_PWR_MB |
RT5645_PWR_BG | RT5645_PWR_VREF2 |
RT5645_PWR_FV1 | RT5645_PWR_FV2, 0x0);
break;
default:
......@@ -2106,8 +2203,7 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
static int rt5645_jack_detect(struct snd_soc_codec *codec,
struct snd_soc_jack *jack)
static int rt5645_jack_detect(struct snd_soc_codec *codec)
{
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
int gpio_state, jack_type = 0;
......@@ -2145,34 +2241,44 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec,
snd_soc_dapm_disable_pin(&codec->dapm, "micbias1");
snd_soc_dapm_disable_pin(&codec->dapm, "micbias2");
if (rt5645->pdata.jd_mode == 0)
snd_soc_dapm_disable_pin(&codec->dapm, "LDO2");
snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
snd_soc_dapm_sync(&codec->dapm);
}
snd_soc_jack_report(rt5645->jack, jack_type, SND_JACK_HEADSET);
snd_soc_jack_report(rt5645->hp_jack, jack_type, SND_JACK_HEADPHONE);
snd_soc_jack_report(rt5645->mic_jack, jack_type, SND_JACK_MICROPHONE);
return 0;
}
int rt5645_set_jack_detect(struct snd_soc_codec *codec,
struct snd_soc_jack *jack)
struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack)
{
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
rt5645->jack = jack;
rt5645_jack_detect(codec, rt5645->jack);
rt5645->hp_jack = hp_jack;
rt5645->mic_jack = mic_jack;
rt5645_jack_detect(codec);
return 0;
}
EXPORT_SYMBOL_GPL(rt5645_set_jack_detect);
static void rt5645_jack_detect_work(struct work_struct *work)
{
struct rt5645_priv *rt5645 =
container_of(work, struct rt5645_priv, jack_detect_work.work);
rt5645_jack_detect(rt5645->codec);
}
static irqreturn_t rt5645_irq(int irq, void *data)
{
struct rt5645_priv *rt5645 = data;
rt5645_jack_detect(rt5645->codec, rt5645->jack);
queue_delayed_work(system_power_efficient_wq,
&rt5645->jack_detect_work, msecs_to_jiffies(250));
return IRQ_HANDLED;
}
......@@ -2187,6 +2293,13 @@ static int rt5645_probe(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
/* for JD function */
if (rt5645->pdata.en_jd_func) {
snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power");
snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
snd_soc_dapm_sync(&codec->dapm);
}
return 0;
}
......@@ -2420,6 +2533,51 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
}
if (rt5645->pdata.en_jd_func) {
regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU,
RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU);
regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1,
RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN);
regmap_update_bits(rt5645->regmap, RT5645_JD_CTRL3,
RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL,
RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL);
regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT);
}
if (rt5645->pdata.jd_mode) {
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_IRQ_JD_1_1_EN, RT5645_IRQ_JD_1_1_EN);
regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
RT5645_JD_PSV_MODE, RT5645_JD_PSV_MODE);
regmap_update_bits(rt5645->regmap, RT5645_HPO_MIXER,
RT5645_IRQ_PSV_MODE, RT5645_IRQ_PSV_MODE);
regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
RT5645_MIC2_OVCD_EN, RT5645_MIC2_OVCD_EN);
regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ);
switch (rt5645->pdata.jd_mode) {
case 1:
regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1,
RT5645_JD1_MODE_MASK,
RT5645_JD1_MODE_0);
break;
case 2:
regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1,
RT5645_JD1_MODE_MASK,
RT5645_JD1_MODE_1);
break;
case 3:
regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1,
RT5645_JD1_MODE_MASK,
RT5645_JD1_MODE_2);
break;
default:
break;
}
}
if (rt5645->i2c->irq) {
ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
......@@ -2438,6 +2596,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n");
}
INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645,
rt5645_dai, ARRAY_SIZE(rt5645_dai));
}
......@@ -2449,6 +2609,8 @@ static int rt5645_i2c_remove(struct i2c_client *i2c)
if (i2c->irq)
free_irq(i2c->irq, rt5645);
cancel_delayed_work_sync(&rt5645->jack_detect_work);
if (gpio_is_valid(rt5645->pdata.hp_det_gpio))
gpio_free(rt5645->pdata.hp_det_gpio);
......
......@@ -594,6 +594,7 @@
#define RT5645_M_DAC1_HM_SFT 14
#define RT5645_M_HPVOL_HM (0x1 << 13)
#define RT5645_M_HPVOL_HM_SFT 13
#define RT5645_IRQ_PSV_MODE (0x1 << 12)
/* SPK Left Mixer Control (0x46) */
#define RT5645_G_RM_L_SM_L_MASK (0x3 << 14)
......@@ -1348,6 +1349,12 @@
#define RT5645_PWR_CLK25M_SFT 4
#define RT5645_PWR_CLK25M_PD (0x0 << 4)
#define RT5645_PWR_CLK25M_PU (0x1 << 4)
#define RT5645_IRQ_CLK_MCLK (0x0 << 3)
#define RT5645_IRQ_CLK_INT (0x1 << 3)
#define RT5645_JD1_MODE_MASK (0x3 << 0)
#define RT5645_JD1_MODE_0 (0x0 << 0)
#define RT5645_JD1_MODE_1 (0x1 << 0)
#define RT5645_JD1_MODE_2 (0x2 << 0)
/* VAD Control 4 (0x9d) */
#define RT5645_VAD_SEL_MASK (0x3 << 8)
......@@ -1636,6 +1643,7 @@
#define RT5645_OT_P_SFT 10
#define RT5645_OT_P_NOR (0x0 << 10)
#define RT5645_OT_P_INV (0x1 << 10)
#define RT5645_IRQ_JD_1_1_EN (0x1 << 9)
/* IRQ Control 2 (0xbe) */
#define RT5645_IRQ_MB1_OC_MASK (0x1 << 15)
......@@ -1853,6 +1861,7 @@
#define RT5645_M_BB_HPF_R_SFT 6
#define RT5645_G_BB_BST_MASK (0x3f)
#define RT5645_G_BB_BST_SFT 0
#define RT5645_G_BB_BST_25DB 0x14
/* MP3 Plus Control 1 (0xd0) */
#define RT5645_M_MP3_L_MASK (0x1 << 15)
......@@ -2116,6 +2125,10 @@ enum {
#define RT5645_RXDP2_SEL_ADC (0x1 << 3)
#define RT5645_RXDP2_SEL_SFT (3)
/* General Control3 (0xfc) */
#define RT5645_JD_PSV_MODE (0x1 << 12)
#define RT5645_IRQ_CLK_GATE_CTRL (0x1 << 11)
#define RT5645_MICINDET_MANU (0x1 << 7)
/* Vendor ID (0xfd) */
#define RT5645_VER_C 0x2
......@@ -2167,7 +2180,9 @@ struct rt5645_priv {
struct rt5645_platform_data pdata;
struct regmap *regmap;
struct i2c_client *i2c;
struct snd_soc_jack *jack;
struct snd_soc_jack *hp_jack;
struct snd_soc_jack *mic_jack;
struct delayed_work jack_detect_work;
int sysclk;
int sysclk_src;
......@@ -2181,6 +2196,6 @@ struct rt5645_priv {
};
int rt5645_set_jack_detect(struct snd_soc_codec *codec,
struct snd_soc_jack *jack);
struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack);
#endif /* __RT5645_H__ */
......@@ -16,6 +16,7 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h>
#include <sound/core.h>
#include <sound/pcm.h>
......@@ -575,6 +576,18 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
}
static int can_use_asrc(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
if (rt5670->sysclk > rt5670->lrck[RT5670_AIF1] * 384)
return 1;
return 0;
}
/* Digital Mixer */
static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = {
SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER,
......@@ -1281,6 +1294,14 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = {
9, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5670_ASRC_1,
8, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5670_ASRC_1,
7, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5670_ASRC_1,
6, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5670_ASRC_1,
5, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5670_ASRC_1,
4, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5670_ASRC_1,
3, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5670_ASRC_1,
......@@ -1595,29 +1616,40 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = {
/* PDM */
SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5670_PWR_DIG2,
RT5670_PWR_PDM1_BIT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2,
RT5670_PWR_PDM2_BIT, 0, NULL, 0),
SND_SOC_DAPM_MUX("PDM1 L Mux", RT5670_PDM_OUT_CTRL,
RT5670_M_PDM1_L_SFT, 1, &rt5670_pdm1_l_mux),
SND_SOC_DAPM_MUX("PDM1 R Mux", RT5670_PDM_OUT_CTRL,
RT5670_M_PDM1_R_SFT, 1, &rt5670_pdm1_r_mux),
SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL,
RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux),
SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL,
RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux),
/* Output Lines */
SND_SOC_DAPM_OUTPUT("HPOL"),
SND_SOC_DAPM_OUTPUT("HPOR"),
SND_SOC_DAPM_OUTPUT("LOUTL"),
SND_SOC_DAPM_OUTPUT("LOUTR"),
};
static const struct snd_soc_dapm_widget rt5670_specific_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2,
RT5670_PWR_PDM2_BIT, 0, NULL, 0),
SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL,
RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux),
SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL,
RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux),
SND_SOC_DAPM_OUTPUT("PDM1L"),
SND_SOC_DAPM_OUTPUT("PDM1R"),
SND_SOC_DAPM_OUTPUT("PDM2L"),
SND_SOC_DAPM_OUTPUT("PDM2R"),
};
static const struct snd_soc_dapm_widget rt5672_specific_dapm_widgets[] = {
SND_SOC_DAPM_PGA("SPO Amp", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_OUTPUT("SPOLP"),
SND_SOC_DAPM_OUTPUT("SPOLN"),
SND_SOC_DAPM_OUTPUT("SPORP"),
SND_SOC_DAPM_OUTPUT("SPORN"),
};
static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
{ "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc },
{ "ADC Stereo2 Filter", NULL, "ADC STO2 ASRC", is_using_asrc },
......@@ -1626,9 +1658,13 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
{ "DAC Mono Left Filter", NULL, "DAC MONO L ASRC", is_using_asrc },
{ "DAC Mono Right Filter", NULL, "DAC MONO R ASRC", is_using_asrc },
{ "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc },
{ "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc },
{ "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc },
{ "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc },
{ "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc },
{ "I2S1", NULL, "I2S1 ASRC" },
{ "I2S2", NULL, "I2S2 ASRC" },
{ "I2S1", NULL, "I2S1 ASRC", can_use_asrc},
{ "I2S2", NULL, "I2S2 ASRC", can_use_asrc},
{ "DMIC1", NULL, "DMIC L1" },
{ "DMIC1", NULL, "DMIC R1" },
......@@ -1970,12 +2006,6 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
{ "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
{ "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" },
{ "PDM1 R Mux", NULL, "PDM1 Power" },
{ "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" },
{ "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" },
{ "PDM2 L Mux", NULL, "PDM2 Power" },
{ "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
{ "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" },
{ "PDM2 R Mux", NULL, "PDM2 Power" },
{ "HP Amp", NULL, "HPO MIX" },
{ "HP Amp", NULL, "Mic Det Power" },
......@@ -1993,13 +2023,30 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
{ "LOUTR", NULL, "LOUT R Playback" },
{ "LOUTL", NULL, "Improve HP Amp Drv" },
{ "LOUTR", NULL, "Improve HP Amp Drv" },
};
static const struct snd_soc_dapm_route rt5670_specific_dapm_routes[] = {
{ "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" },
{ "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" },
{ "PDM2 L Mux", NULL, "PDM2 Power" },
{ "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
{ "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" },
{ "PDM2 R Mux", NULL, "PDM2 Power" },
{ "PDM1L", NULL, "PDM1 L Mux" },
{ "PDM1R", NULL, "PDM1 R Mux" },
{ "PDM2L", NULL, "PDM2 L Mux" },
{ "PDM2R", NULL, "PDM2 R Mux" },
};
static const struct snd_soc_dapm_route rt5672_specific_dapm_routes[] = {
{ "SPO Amp", NULL, "PDM1 L Mux" },
{ "SPO Amp", NULL, "PDM1 R Mux" },
{ "SPOLP", NULL, "SPO Amp" },
{ "SPOLN", NULL, "SPO Amp" },
{ "SPORP", NULL, "SPO Amp" },
{ "SPORN", NULL, "SPO Amp" },
};
static int rt5670_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
......@@ -2287,6 +2334,8 @@ static int rt5670_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
static int rt5670_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
switch (level) {
case SND_SOC_BIAS_PREPARE:
if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
......@@ -2308,16 +2357,27 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,
}
break;
case SND_SOC_BIAS_STANDBY:
snd_soc_write(codec, RT5670_PWR_DIG1, 0x0000);
snd_soc_write(codec, RT5670_PWR_DIG2, 0x0001);
snd_soc_write(codec, RT5670_PWR_VOL, 0x0000);
snd_soc_write(codec, RT5670_PWR_MIXER, 0x0001);
snd_soc_write(codec, RT5670_PWR_ANLG1, 0x2800);
snd_soc_write(codec, RT5670_PWR_ANLG2, 0x0004);
snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0);
snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
RT5670_PWR_VREF1 | RT5670_PWR_VREF2 |
RT5670_PWR_FV1 | RT5670_PWR_FV2, 0);
snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
RT5670_LDO_SEL_MASK, 0x1);
break;
case SND_SOC_BIAS_OFF:
if (rt5670->pdata.jd_mode)
snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
RT5670_PWR_VREF1 | RT5670_PWR_MB |
RT5670_PWR_BG | RT5670_PWR_VREF2 |
RT5670_PWR_FV1 | RT5670_PWR_FV2,
RT5670_PWR_MB | RT5670_PWR_BG);
else
snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
RT5670_PWR_VREF1 | RT5670_PWR_MB |
RT5670_PWR_BG | RT5670_PWR_VREF2 |
RT5670_PWR_FV1 | RT5670_PWR_FV2, 0);
snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0);
break;
default:
break;
......@@ -2331,6 +2391,29 @@ static int rt5670_probe(struct snd_soc_codec *codec)
{
struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
switch (snd_soc_read(codec, RT5670_RESET) & RT5670_ID_MASK) {
case RT5670_ID_5670:
case RT5670_ID_5671:
snd_soc_dapm_new_controls(&codec->dapm,
rt5670_specific_dapm_widgets,
ARRAY_SIZE(rt5670_specific_dapm_widgets));
snd_soc_dapm_add_routes(&codec->dapm,
rt5670_specific_dapm_routes,
ARRAY_SIZE(rt5670_specific_dapm_routes));
break;
case RT5670_ID_5672:
snd_soc_dapm_new_controls(&codec->dapm,
rt5672_specific_dapm_widgets,
ARRAY_SIZE(rt5672_specific_dapm_widgets));
snd_soc_dapm_add_routes(&codec->dapm,
rt5672_specific_dapm_routes,
ARRAY_SIZE(rt5672_specific_dapm_routes));
break;
default:
dev_err(codec->dev,
"The driver is for RT5670 RT5671 or RT5672 only\n");
return -ENODEV;
}
rt5670->codec = codec;
return 0;
......@@ -2452,10 +2535,20 @@ static const struct regmap_config rt5670_regmap = {
static const struct i2c_device_id rt5670_i2c_id[] = {
{ "rt5670", 0 },
{ "rt5671", 0 },
{ "rt5672", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id);
#ifdef CONFIG_ACPI
static struct acpi_device_id rt5670_acpi_match[] = {
{ "10EC5670", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
#endif
static int rt5670_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
......@@ -2644,6 +2737,7 @@ static struct i2c_driver rt5670_i2c_driver = {
.driver = {
.name = "rt5670",
.owner = THIS_MODULE,
.acpi_match_table = ACPI_PTR(rt5670_acpi_match),
},
.probe = rt5670_i2c_probe,
.remove = rt5670_i2c_remove,
......
......@@ -228,6 +228,12 @@
#define RT5670_R_VOL_MASK (0x3f)
#define RT5670_R_VOL_SFT 0
/* SW Reset & Device ID (0x00) */
#define RT5670_ID_MASK (0x3 << 1)
#define RT5670_ID_5670 (0x0 << 1)
#define RT5670_ID_5672 (0x1 << 1)
#define RT5670_ID_5671 (0x2 << 1)
/* Combo Jack Control 1 (0x0a) */
#define RT5670_CBJ_BST1_MASK (0xf << 12)
#define RT5670_CBJ_BST1_SFT (12)
......
/*
* rt5677-spi.c -- RT5677 ALSA SoC audio codec driver
*
* Copyright 2013 Realtek Semiconductor Corp.
* Author: Oder Chiou <oder_chiou@realtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/input.h>
#include <linux/spi/spi.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_qos.h>
#include <linux/sysfs.h>
#include <linux/clk.h>
#include <linux/firmware.h>
#include "rt5677-spi.h"
static struct spi_device *g_spi;
/**
* rt5677_spi_write - Write data to SPI.
* @txbuf: Data Buffer for writing.
* @len: Data length.
*
*
* Returns true for success.
*/
int rt5677_spi_write(u8 *txbuf, size_t len)
{
int status;
status = spi_write(g_spi, txbuf, len);
if (status)
dev_err(&g_spi->dev, "rt5677_spi_write error %d\n", status);
return status;
}
EXPORT_SYMBOL_GPL(rt5677_spi_write);
/**
* rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address.
* @addr: Start address.
* @txbuf: Data Buffer for writng.
* @len: Data length, it must be a multiple of 8.
*
*
* Returns true for success.
*/
int rt5677_spi_burst_write(u32 addr, const struct firmware *fw)
{
u8 spi_cmd = RT5677_SPI_CMD_BURST_WRITE;
u8 *write_buf;
unsigned int i, end, offset = 0;
write_buf = kmalloc(RT5677_SPI_BUF_LEN + 6, GFP_KERNEL);
if (write_buf == NULL)
return -ENOMEM;
while (offset < fw->size) {
if (offset + RT5677_SPI_BUF_LEN <= fw->size)
end = RT5677_SPI_BUF_LEN;
else
end = fw->size % RT5677_SPI_BUF_LEN;
write_buf[0] = spi_cmd;
write_buf[1] = ((addr + offset) & 0xff000000) >> 24;
write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16;
write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8;
write_buf[4] = ((addr + offset) & 0x000000ff) >> 0;
for (i = 0; i < end; i += 8) {
write_buf[i + 12] = fw->data[offset + i + 0];
write_buf[i + 11] = fw->data[offset + i + 1];
write_buf[i + 10] = fw->data[offset + i + 2];
write_buf[i + 9] = fw->data[offset + i + 3];
write_buf[i + 8] = fw->data[offset + i + 4];
write_buf[i + 7] = fw->data[offset + i + 5];
write_buf[i + 6] = fw->data[offset + i + 6];
write_buf[i + 5] = fw->data[offset + i + 7];
}
write_buf[end + 5] = spi_cmd;
rt5677_spi_write(write_buf, end + 6);
offset += RT5677_SPI_BUF_LEN;
}
kfree(write_buf);
return 0;
}
EXPORT_SYMBOL_GPL(rt5677_spi_burst_write);
static int rt5677_spi_probe(struct spi_device *spi)
{
g_spi = spi;
return 0;
}
static struct spi_driver rt5677_spi_driver = {
.driver = {
.name = "rt5677",
.owner = THIS_MODULE,
},
.probe = rt5677_spi_probe,
};
module_spi_driver(rt5677_spi_driver);
MODULE_DESCRIPTION("ASoC RT5677 SPI driver");
MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
MODULE_LICENSE("GPL v2");
/*
* rt5677-spi.h -- RT5677 ALSA SoC audio codec driver
*
* Copyright 2013 Realtek Semiconductor Corp.
* Author: Oder Chiou <oder_chiou@realtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __RT5677_SPI_H__
#define __RT5677_SPI_H__
#define RT5677_SPI_BUF_LEN 240
#define RT5677_SPI_CMD_BURST_WRITE 0x05
int rt5677_spi_write(u8 *txbuf, size_t len);
int rt5677_spi_burst_write(u32 addr, const struct firmware *fw);
#endif /* __RT5677_SPI_H__ */
......@@ -20,6 +20,7 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/firmware.h>
#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
......@@ -31,6 +32,7 @@
#include "rl6231.h"
#include "rt5677.h"
#include "rt5677-spi.h"
#define RT5677_DEVICE_ID 0x6327
......@@ -53,6 +55,7 @@ static const struct regmap_range_cfg rt5677_ranges[] = {
};
static const struct reg_default init_list[] = {
{RT5677_ASRC_12, 0x0018},
{RT5677_PR_BASE + 0x3d, 0x364d},
{RT5677_PR_BASE + 0x17, 0x4fc0},
{RT5677_PR_BASE + 0x13, 0x0312},
......@@ -171,7 +174,7 @@ static const struct reg_default rt5677_reg[] = {
{RT5677_ASRC_9 , 0x0000},
{RT5677_ASRC_10 , 0x0000},
{RT5677_ASRC_11 , 0x0000},
{RT5677_ASRC_12 , 0x0008},
{RT5677_ASRC_12 , 0x0018},
{RT5677_ASRC_13 , 0x0000},
{RT5677_ASRC_14 , 0x0000},
{RT5677_ASRC_15 , 0x0000},
......@@ -537,10 +540,232 @@ static bool rt5677_readable_register(struct device *dev, unsigned int reg)
}
}
/**
* rt5677_dsp_mode_i2c_write_addr - Write value to address on DSP mode.
* @rt5677: Private Data.
* @addr: Address index.
* @value: Address data.
*
*
* Returns 0 for success or negative error code.
*/
static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677,
unsigned int addr, unsigned int value, unsigned int opcode)
{
struct snd_soc_codec *codec = rt5677->codec;
int ret;
mutex_lock(&rt5677->dsp_cmd_lock);
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB,
addr >> 16);
if (ret < 0) {
dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret);
goto err;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB,
addr & 0xffff);
if (ret < 0) {
dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret);
goto err;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB,
value >> 16);
if (ret < 0) {
dev_err(codec->dev, "Failed to set data msb value: %d\n", ret);
goto err;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB,
value & 0xffff);
if (ret < 0) {
dev_err(codec->dev, "Failed to set data lsb value: %d\n", ret);
goto err;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE,
opcode);
if (ret < 0) {
dev_err(codec->dev, "Failed to set op code value: %d\n", ret);
goto err;
}
err:
mutex_unlock(&rt5677->dsp_cmd_lock);
return ret;
}
/**
* rt5677_dsp_mode_i2c_read_addr - Read value from address on DSP mode.
* rt5677: Private Data.
* @addr: Address index.
* @value: Address data.
*
*
* Returns 0 for success or negative error code.
*/
static int rt5677_dsp_mode_i2c_read_addr(
struct rt5677_priv *rt5677, unsigned int addr, unsigned int *value)
{
struct snd_soc_codec *codec = rt5677->codec;
int ret;
unsigned int msb, lsb;
mutex_lock(&rt5677->dsp_cmd_lock);
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB,
addr >> 16);
if (ret < 0) {
dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret);
goto err;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB,
addr & 0xffff);
if (ret < 0) {
dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret);
goto err;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE,
0x0002);
if (ret < 0) {
dev_err(codec->dev, "Failed to set op code value: %d\n", ret);
goto err;
}
regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, &msb);
regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, &lsb);
*value = (msb << 16) | lsb;
err:
mutex_unlock(&rt5677->dsp_cmd_lock);
return ret;
}
/**
* rt5677_dsp_mode_i2c_write - Write register on DSP mode.
* rt5677: Private Data.
* @reg: Register index.
* @value: Register data.
*
*
* Returns 0 for success or negative error code.
*/
static int rt5677_dsp_mode_i2c_write(struct rt5677_priv *rt5677,
unsigned int reg, unsigned int value)
{
return rt5677_dsp_mode_i2c_write_addr(rt5677, 0x18020000 + reg * 2,
value, 0x0001);
}
/**
* rt5677_dsp_mode_i2c_read - Read register on DSP mode.
* @codec: SoC audio codec device.
* @reg: Register index.
* @value: Register data.
*
*
* Returns 0 for success or negative error code.
*/
static int rt5677_dsp_mode_i2c_read(
struct rt5677_priv *rt5677, unsigned int reg, unsigned int *value)
{
int ret = rt5677_dsp_mode_i2c_read_addr(rt5677, 0x18020000 + reg * 2,
value);
*value &= 0xffff;
return ret;
}
static void rt5677_set_dsp_mode(struct snd_soc_codec *codec, bool on)
{
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
if (on) {
regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x2);
rt5677->is_dsp_mode = true;
} else {
regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x0);
rt5677->is_dsp_mode = false;
}
}
static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on)
{
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
static bool activity;
int ret;
if (on && !activity) {
activity = true;
regcache_cache_only(rt5677->regmap, false);
regcache_cache_bypass(rt5677->regmap, true);
regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x1);
regmap_update_bits(rt5677->regmap,
RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0f00);
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
RT5677_LDO1_SEL_MASK, 0x0);
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
RT5677_PWR_LDO1, RT5677_PWR_LDO1);
regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC);
regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2,
RT5677_PLL2_PR_SRC_MASK | RT5677_DSP_CLK_SRC_MASK,
RT5677_PLL2_PR_SRC_MCLK2 | RT5677_DSP_CLK_SRC_BYPASS);
regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff);
regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07fd);
rt5677_set_dsp_mode(codec, true);
ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1,
codec->dev);
if (ret == 0) {
rt5677_spi_burst_write(0x50000000, rt5677->fw1);
release_firmware(rt5677->fw1);
}
ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2,
codec->dev);
if (ret == 0) {
rt5677_spi_burst_write(0x60000000, rt5677->fw2);
release_firmware(rt5677->fw2);
}
regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x0);
regcache_cache_bypass(rt5677->regmap, false);
regcache_cache_only(rt5677->regmap, true);
} else if (!on && activity) {
activity = false;
regcache_cache_only(rt5677->regmap, false);
regcache_cache_bypass(rt5677->regmap, true);
regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x1);
rt5677_set_dsp_mode(codec, false);
regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x0001);
regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
regcache_cache_bypass(rt5677->regmap, false);
regcache_mark_dirty(rt5677->regmap);
regcache_sync(rt5677->regmap);
}
return 0;
}
static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);
static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0);
......@@ -556,6 +781,31 @@ static unsigned int bst_tlv[] = {
8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
};
static int rt5677_dsp_vad_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = rt5677->dsp_vad_en;
return 0;
}
static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0];
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
rt5677_set_dsp_vad(codec, rt5677->dsp_vad_en);
return 0;
}
static const struct snd_kcontrol_new rt5677_snd_controls[] = {
/* OUTPUT Control */
SOC_SINGLE("OUT1 Playback Switch", RT5677_LOUT1,
......@@ -567,13 +817,13 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = {
/* DAC Digital Volume */
SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5677_DAC1_DIG_VOL,
RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv),
RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5677_DAC2_DIG_VOL,
RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv),
RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
SOC_DOUBLE_TLV("DAC3 Playback Volume", RT5677_DAC3_DIG_VOL,
RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv),
RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
SOC_DOUBLE_TLV("DAC4 Playback Volume", RT5677_DAC4_DIG_VOL,
RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv),
RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
/* IN1/IN2 Control */
SOC_SINGLE_TLV("IN1 Boost", RT5677_IN1, RT5677_BST_SFT1, 8, 0, bst_tlv),
......@@ -592,19 +842,19 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = {
RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1),
SOC_DOUBLE_TLV("ADC1 Capture Volume", RT5677_STO1_ADC_DIG_VOL,
RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0,
RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
adc_vol_tlv),
SOC_DOUBLE_TLV("ADC2 Capture Volume", RT5677_STO2_ADC_DIG_VOL,
RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0,
RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
adc_vol_tlv),
SOC_DOUBLE_TLV("ADC3 Capture Volume", RT5677_STO3_ADC_DIG_VOL,
RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0,
RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
adc_vol_tlv),
SOC_DOUBLE_TLV("ADC4 Capture Volume", RT5677_STO4_ADC_DIG_VOL,
RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0,
RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
adc_vol_tlv),
SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5677_MONO_ADC_DIG_VOL,
RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 127, 0,
RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 63, 0,
adc_vol_tlv),
/* Sidetone Control */
......@@ -627,6 +877,9 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = {
SOC_DOUBLE_TLV("Mono ADC Boost Volume", RT5677_ADC_BST_CTRL2,
RT5677_MONO_ADC_L_BST_SFT, RT5677_MONO_ADC_R_BST_SFT, 3, 0,
adc_bst_tlv),
SOC_SINGLE_EXT("DSP VAD Switch", SND_SOC_NOPM, 0, 1, 0,
rt5677_dsp_vad_get, rt5677_dsp_vad_put),
};
/**
......@@ -1443,7 +1696,7 @@ static SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5677_pdm2_r_mux =
SOC_DAPM_ENUM("PDM2 Source", rt5677_pdm2_r_enum);
/* TDM IF1/2 SLB ADC1 Data Selection */ /* MX-3C MX-41 [5:4] MX-08 [1:0]*/
/* TDM IF1/2 SLB ADC1 Data Selection */ /* MX-3C MX-41 [5:4] MX-08 [1:0] */
static const char * const rt5677_if12_adc1_src[] = {
"STO1 ADC MIX", "OB01", "VAD ADC"
};
......@@ -1547,7 +1800,7 @@ static SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5677_slb_adc4_mux =
SOC_DAPM_ENUM("SLB ADC4 Source", rt5677_slb_adc4_enum);
/* Interface3/4 ADC Data Input */ /* MX-2F [3:0] MX-30 [7:4]*/
/* Interface3/4 ADC Data Input */ /* MX-2F [3:0] MX-30 [7:4] */
static const char * const rt5677_if34_adc_src[] = {
"STO1 ADC MIX", "STO2 ADC MIX", "STO3 ADC MIX", "STO4 ADC MIX",
"MONO ADC MIX", "OB01", "OB23", "VAD ADC"
......@@ -1567,6 +1820,213 @@ static SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5677_if4_adc_mux =
SOC_DAPM_ENUM("IF4 ADC Source", rt5677_if4_adc_enum);
/* TDM IF1/2 ADC Data Selection */ /* MX-3B MX-40 [7:6][5:4][3:2][1:0] */
static const char * const rt5677_if12_adc_swap_src[] = {
"L/R", "R/L", "L/L", "R/R"
};
static SOC_ENUM_SINGLE_DECL(
rt5677_if1_adc1_swap_enum, RT5677_TDM1_CTRL1,
RT5677_IF1_ADC1_SWAP_SFT, rt5677_if12_adc_swap_src);
static const struct snd_kcontrol_new rt5677_if1_adc1_swap_mux =
SOC_DAPM_ENUM("IF1 ADC1 Swap Source", rt5677_if1_adc1_swap_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if1_adc2_swap_enum, RT5677_TDM1_CTRL1,
RT5677_IF1_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src);
static const struct snd_kcontrol_new rt5677_if1_adc2_swap_mux =
SOC_DAPM_ENUM("IF1 ADC2 Swap Source", rt5677_if1_adc2_swap_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if1_adc3_swap_enum, RT5677_TDM1_CTRL1,
RT5677_IF1_ADC3_SWAP_SFT, rt5677_if12_adc_swap_src);
static const struct snd_kcontrol_new rt5677_if1_adc3_swap_mux =
SOC_DAPM_ENUM("IF1 ADC3 Swap Source", rt5677_if1_adc3_swap_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if1_adc4_swap_enum, RT5677_TDM1_CTRL1,
RT5677_IF1_ADC4_SWAP_SFT, rt5677_if12_adc_swap_src);
static const struct snd_kcontrol_new rt5677_if1_adc4_swap_mux =
SOC_DAPM_ENUM("IF1 ADC4 Swap Source", rt5677_if1_adc4_swap_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if2_adc1_swap_enum, RT5677_TDM2_CTRL1,
RT5677_IF1_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src);
static const struct snd_kcontrol_new rt5677_if2_adc1_swap_mux =
SOC_DAPM_ENUM("IF1 ADC2 Swap Source", rt5677_if2_adc1_swap_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if2_adc2_swap_enum, RT5677_TDM2_CTRL1,
RT5677_IF2_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src);
static const struct snd_kcontrol_new rt5677_if2_adc2_swap_mux =
SOC_DAPM_ENUM("IF2 ADC2 Swap Source", rt5677_if2_adc2_swap_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if2_adc3_swap_enum, RT5677_TDM2_CTRL1,
RT5677_IF2_ADC3_SWAP_SFT, rt5677_if12_adc_swap_src);
static const struct snd_kcontrol_new rt5677_if2_adc3_swap_mux =
SOC_DAPM_ENUM("IF2 ADC3 Swap Source", rt5677_if2_adc3_swap_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if2_adc4_swap_enum, RT5677_TDM2_CTRL1,
RT5677_IF2_ADC4_SWAP_SFT, rt5677_if12_adc_swap_src);
static const struct snd_kcontrol_new rt5677_if2_adc4_swap_mux =
SOC_DAPM_ENUM("IF2 ADC4 Swap Source", rt5677_if2_adc4_swap_enum);
/* TDM IF1 ADC Data Selection */ /* MX-3C [2:0] */
static const char * const rt5677_if1_adc_tdm_swap_src[] = {
"1/2/3/4", "2/1/3/4", "2/3/1/4", "4/1/2/3", "1/3/2/4", "1/4/2/3",
"3/1/2/4", "3/4/1/2"
};
static SOC_ENUM_SINGLE_DECL(
rt5677_if1_adc_tdm_swap_enum, RT5677_TDM1_CTRL2,
RT5677_IF1_ADC_CTRL_SFT, rt5677_if1_adc_tdm_swap_src);
static const struct snd_kcontrol_new rt5677_if1_adc_tdm_swap_mux =
SOC_DAPM_ENUM("IF1 ADC TDM Swap Source", rt5677_if1_adc_tdm_swap_enum);
/* TDM IF2 ADC Data Selection */ /* MX-41[2:0] */
static const char * const rt5677_if2_adc_tdm_swap_src[] = {
"1/2/3/4", "2/1/3/4", "3/1/2/4", "4/1/2/3", "1/3/2/4", "1/4/2/3",
"2/3/1/4", "3/4/1/2"
};
static SOC_ENUM_SINGLE_DECL(
rt5677_if2_adc_tdm_swap_enum, RT5677_TDM2_CTRL2,
RT5677_IF2_ADC_CTRL_SFT, rt5677_if2_adc_tdm_swap_src);
static const struct snd_kcontrol_new rt5677_if2_adc_tdm_swap_mux =
SOC_DAPM_ENUM("IF2 ADC TDM Swap Source", rt5677_if2_adc_tdm_swap_enum);
/* TDM IF1/2 DAC Data Selection */ /* MX-3E[14:12][10:8][6:4][2:0]
MX-3F[14:12][10:8][6:4][2:0]
MX-43[14:12][10:8][6:4][2:0]
MX-44[14:12][10:8][6:4][2:0] */
static const char * const rt5677_if12_dac_tdm_sel_src[] = {
"Slot0", "Slot1", "Slot2", "Slot3", "Slot4", "Slot5", "Slot6", "Slot7"
};
static SOC_ENUM_SINGLE_DECL(
rt5677_if1_dac0_tdm_sel_enum, RT5677_TDM1_CTRL4,
RT5677_IF1_DAC0_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if1_dac0_tdm_sel_mux =
SOC_DAPM_ENUM("IF1 DAC0 TDM Source", rt5677_if1_dac0_tdm_sel_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if1_dac1_tdm_sel_enum, RT5677_TDM1_CTRL4,
RT5677_IF1_DAC1_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if1_dac1_tdm_sel_mux =
SOC_DAPM_ENUM("IF1 DAC1 TDM Source", rt5677_if1_dac1_tdm_sel_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if1_dac2_tdm_sel_enum, RT5677_TDM1_CTRL4,
RT5677_IF1_DAC2_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if1_dac2_tdm_sel_mux =
SOC_DAPM_ENUM("IF1 DAC2 TDM Source", rt5677_if1_dac2_tdm_sel_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if1_dac3_tdm_sel_enum, RT5677_TDM1_CTRL4,
RT5677_IF1_DAC3_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if1_dac3_tdm_sel_mux =
SOC_DAPM_ENUM("IF1 DAC3 TDM Source", rt5677_if1_dac3_tdm_sel_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if1_dac4_tdm_sel_enum, RT5677_TDM1_CTRL5,
RT5677_IF1_DAC4_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if1_dac4_tdm_sel_mux =
SOC_DAPM_ENUM("IF1 DAC4 TDM Source", rt5677_if1_dac4_tdm_sel_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if1_dac5_tdm_sel_enum, RT5677_TDM1_CTRL5,
RT5677_IF1_DAC5_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if1_dac5_tdm_sel_mux =
SOC_DAPM_ENUM("IF1 DAC5 TDM Source", rt5677_if1_dac5_tdm_sel_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if1_dac6_tdm_sel_enum, RT5677_TDM1_CTRL5,
RT5677_IF1_DAC6_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if1_dac6_tdm_sel_mux =
SOC_DAPM_ENUM("IF1 DAC6 TDM Source", rt5677_if1_dac6_tdm_sel_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if1_dac7_tdm_sel_enum, RT5677_TDM1_CTRL5,
RT5677_IF1_DAC7_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if1_dac7_tdm_sel_mux =
SOC_DAPM_ENUM("IF1 DAC7 TDM Source", rt5677_if1_dac7_tdm_sel_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if2_dac0_tdm_sel_enum, RT5677_TDM2_CTRL4,
RT5677_IF2_DAC0_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if2_dac0_tdm_sel_mux =
SOC_DAPM_ENUM("IF2 DAC0 TDM Source", rt5677_if2_dac0_tdm_sel_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if2_dac1_tdm_sel_enum, RT5677_TDM2_CTRL4,
RT5677_IF2_DAC1_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if2_dac1_tdm_sel_mux =
SOC_DAPM_ENUM("IF2 DAC1 TDM Source", rt5677_if2_dac1_tdm_sel_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if2_dac2_tdm_sel_enum, RT5677_TDM2_CTRL4,
RT5677_IF2_DAC2_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if2_dac2_tdm_sel_mux =
SOC_DAPM_ENUM("IF2 DAC2 TDM Source", rt5677_if2_dac2_tdm_sel_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if2_dac3_tdm_sel_enum, RT5677_TDM2_CTRL4,
RT5677_IF2_DAC3_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if2_dac3_tdm_sel_mux =
SOC_DAPM_ENUM("IF2 DAC3 TDM Source", rt5677_if2_dac3_tdm_sel_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if2_dac4_tdm_sel_enum, RT5677_TDM2_CTRL5,
RT5677_IF2_DAC4_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if2_dac4_tdm_sel_mux =
SOC_DAPM_ENUM("IF2 DAC4 TDM Source", rt5677_if2_dac4_tdm_sel_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if2_dac5_tdm_sel_enum, RT5677_TDM2_CTRL5,
RT5677_IF2_DAC5_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if2_dac5_tdm_sel_mux =
SOC_DAPM_ENUM("IF2 DAC5 TDM Source", rt5677_if2_dac5_tdm_sel_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if2_dac6_tdm_sel_enum, RT5677_TDM2_CTRL5,
RT5677_IF2_DAC6_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if2_dac6_tdm_sel_mux =
SOC_DAPM_ENUM("IF2 DAC6 TDM Source", rt5677_if2_dac6_tdm_sel_enum);
static SOC_ENUM_SINGLE_DECL(
rt5677_if2_dac7_tdm_sel_enum, RT5677_TDM2_CTRL5,
RT5677_IF2_DAC7_SFT, rt5677_if12_dac_tdm_sel_src);
static const struct snd_kcontrol_new rt5677_if2_dac7_tdm_sel_mux =
SOC_DAPM_ENUM("IF2 DAC7 TDM Source", rt5677_if2_dac7_tdm_sel_enum);
static int rt5677_bst1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
......@@ -1678,6 +2138,77 @@ static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w,
return 0;
}
static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
unsigned int value;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
regmap_read(rt5677->regmap, RT5677_TDM1_CTRL2, &value);
if (value & RT5677_IF1_ADC_CTRL_MASK)
regmap_update_bits(rt5677->regmap, RT5677_TDM1_CTRL1,
RT5677_IF1_ADC_MODE_MASK,
RT5677_IF1_ADC_MODE_TDM);
break;
default:
return 0;
}
return 0;
}
static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
unsigned int value;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
regmap_read(rt5677->regmap, RT5677_TDM2_CTRL2, &value);
if (value & RT5677_IF2_ADC_CTRL_MASK)
regmap_update_bits(rt5677->regmap, RT5677_TDM2_CTRL1,
RT5677_IF2_ADC_MODE_MASK,
RT5677_IF2_ADC_MODE_TDM);
break;
default:
return 0;
}
return 0;
}
static int rt5677_vref_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
if (codec->dapm.bias_level != SND_SOC_BIAS_ON &&
!rt5677->is_vref_slow) {
mdelay(20);
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
RT5677_PWR_FV1 | RT5677_PWR_FV2,
RT5677_PWR_FV1 | RT5677_PWR_FV2);
rt5677->is_vref_slow = true;
}
break;
default:
return 0;
}
return 0;
}
static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT,
0, rt5677_set_pll1_event, SND_SOC_DAPM_POST_PMU),
......@@ -1837,10 +2368,8 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
SND_SOC_DAPM_PGA("Stereo4 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
/* DSP */
SND_SOC_DAPM_MUX("IB9 Mux", SND_SOC_NOPM, 0, 0,
......@@ -1963,6 +2492,17 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
&rt5677_if1_adc3_mux),
SND_SOC_DAPM_MUX("IF1 ADC4 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if1_adc4_mux),
SND_SOC_DAPM_MUX("IF1 ADC1 Swap Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if1_adc1_swap_mux),
SND_SOC_DAPM_MUX("IF1 ADC2 Swap Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if1_adc2_swap_mux),
SND_SOC_DAPM_MUX("IF1 ADC3 Swap Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if1_adc3_swap_mux),
SND_SOC_DAPM_MUX("IF1 ADC4 Swap Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if1_adc4_swap_mux),
SND_SOC_DAPM_MUX_E("IF1 ADC TDM Swap Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if1_adc_tdm_swap_mux, rt5677_if1_adc_tdm_event,
SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MUX("IF2 ADC1 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_adc1_mux),
SND_SOC_DAPM_MUX("IF2 ADC2 Mux", SND_SOC_NOPM, 0, 0,
......@@ -1971,6 +2511,17 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
&rt5677_if2_adc3_mux),
SND_SOC_DAPM_MUX("IF2 ADC4 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_adc4_mux),
SND_SOC_DAPM_MUX("IF2 ADC1 Swap Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_adc1_swap_mux),
SND_SOC_DAPM_MUX("IF2 ADC2 Swap Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_adc2_swap_mux),
SND_SOC_DAPM_MUX("IF2 ADC3 Swap Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_adc3_swap_mux),
SND_SOC_DAPM_MUX("IF2 ADC4 Swap Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_adc4_swap_mux),
SND_SOC_DAPM_MUX_E("IF2 ADC TDM Swap Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_adc_tdm_swap_mux, rt5677_if2_adc_tdm_event,
SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if3_adc_mux),
SND_SOC_DAPM_MUX("IF4 ADC Mux", SND_SOC_NOPM, 0, 0,
......@@ -1984,6 +2535,40 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
SND_SOC_DAPM_MUX("SLB ADC4 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_slb_adc4_mux),
SND_SOC_DAPM_MUX("IF1 DAC0 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if1_dac0_tdm_sel_mux),
SND_SOC_DAPM_MUX("IF1 DAC1 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if1_dac1_tdm_sel_mux),
SND_SOC_DAPM_MUX("IF1 DAC2 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if1_dac2_tdm_sel_mux),
SND_SOC_DAPM_MUX("IF1 DAC3 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if1_dac3_tdm_sel_mux),
SND_SOC_DAPM_MUX("IF1 DAC4 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if1_dac4_tdm_sel_mux),
SND_SOC_DAPM_MUX("IF1 DAC5 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if1_dac5_tdm_sel_mux),
SND_SOC_DAPM_MUX("IF1 DAC6 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if1_dac6_tdm_sel_mux),
SND_SOC_DAPM_MUX("IF1 DAC7 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if1_dac7_tdm_sel_mux),
SND_SOC_DAPM_MUX("IF2 DAC0 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_dac0_tdm_sel_mux),
SND_SOC_DAPM_MUX("IF2 DAC1 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_dac1_tdm_sel_mux),
SND_SOC_DAPM_MUX("IF2 DAC2 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_dac2_tdm_sel_mux),
SND_SOC_DAPM_MUX("IF2 DAC3 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_dac3_tdm_sel_mux),
SND_SOC_DAPM_MUX("IF2 DAC4 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_dac4_tdm_sel_mux),
SND_SOC_DAPM_MUX("IF2 DAC5 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_dac5_tdm_sel_mux),
SND_SOC_DAPM_MUX("IF2 DAC6 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_dac6_tdm_sel_mux),
SND_SOC_DAPM_MUX("IF2 DAC7 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_dac7_tdm_sel_mux),
/* Audio Interface */
SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
......@@ -2109,13 +2694,20 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
SND_SOC_DAPM_MUX("PDM2 R Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM2_R_SFT,
1, &rt5677_pdm2_r_mux),
SND_SOC_DAPM_PGA_S("LOUT1 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO1_BIT,
SND_SOC_DAPM_PGA_S("LOUT1 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO1_BIT,
0, NULL, 0),
SND_SOC_DAPM_PGA_S("LOUT2 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO2_BIT,
SND_SOC_DAPM_PGA_S("LOUT2 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO2_BIT,
0, NULL, 0),
SND_SOC_DAPM_PGA_S("LOUT3 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO3_BIT,
SND_SOC_DAPM_PGA_S("LOUT3 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO3_BIT,
0, NULL, 0),
SND_SOC_DAPM_PGA_S("LOUT1 vref", 1, SND_SOC_NOPM, 0, 0,
rt5677_vref_event, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_S("LOUT2 vref", 1, SND_SOC_NOPM, 0, 0,
rt5677_vref_event, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_S("LOUT3 vref", 1, SND_SOC_NOPM, 0, 0,
rt5677_vref_event, SND_SOC_DAPM_POST_PMU),
/* Output Lines */
SND_SOC_DAPM_OUTPUT("LOUT1"),
SND_SOC_DAPM_OUTPUT("LOUT2"),
......@@ -2124,6 +2716,8 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("PDM1R"),
SND_SOC_DAPM_OUTPUT("PDM2L"),
SND_SOC_DAPM_OUTPUT("PDM2R"),
SND_SOC_DAPM_POST("vref", rt5677_vref_event),
};
static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
......@@ -2354,11 +2948,42 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "IF1 ADC4 Mux", "OB67", "OB67" },
{ "IF1 ADC4 Mux", "OB01", "OB01 Bypass Mux" },
{ "IF1 ADC1 Swap Mux", "L/R", "IF1 ADC1 Mux" },
{ "IF1 ADC1 Swap Mux", "R/L", "IF1 ADC1 Mux" },
{ "IF1 ADC1 Swap Mux", "L/L", "IF1 ADC1 Mux" },
{ "IF1 ADC1 Swap Mux", "R/R", "IF1 ADC1 Mux" },
{ "IF1 ADC2 Swap Mux", "L/R", "IF1 ADC2 Mux" },
{ "IF1 ADC2 Swap Mux", "R/L", "IF1 ADC2 Mux" },
{ "IF1 ADC2 Swap Mux", "L/L", "IF1 ADC2 Mux" },
{ "IF1 ADC2 Swap Mux", "R/R", "IF1 ADC2 Mux" },
{ "IF1 ADC3 Swap Mux", "L/R", "IF1 ADC3 Mux" },
{ "IF1 ADC3 Swap Mux", "R/L", "IF1 ADC3 Mux" },
{ "IF1 ADC3 Swap Mux", "L/L", "IF1 ADC3 Mux" },
{ "IF1 ADC3 Swap Mux", "R/R", "IF1 ADC3 Mux" },
{ "IF1 ADC4 Swap Mux", "L/R", "IF1 ADC4 Mux" },
{ "IF1 ADC4 Swap Mux", "R/L", "IF1 ADC4 Mux" },
{ "IF1 ADC4 Swap Mux", "L/L", "IF1 ADC4 Mux" },
{ "IF1 ADC4 Swap Mux", "R/R", "IF1 ADC4 Mux" },
{ "IF1 ADC", NULL, "IF1 ADC1 Swap Mux" },
{ "IF1 ADC", NULL, "IF1 ADC2 Swap Mux" },
{ "IF1 ADC", NULL, "IF1 ADC3 Swap Mux" },
{ "IF1 ADC", NULL, "IF1 ADC4 Swap Mux" },
{ "IF1 ADC TDM Swap Mux", "1/2/3/4", "IF1 ADC" },
{ "IF1 ADC TDM Swap Mux", "2/1/3/4", "IF1 ADC" },
{ "IF1 ADC TDM Swap Mux", "2/3/1/4", "IF1 ADC" },
{ "IF1 ADC TDM Swap Mux", "4/1/2/3", "IF1 ADC" },
{ "IF1 ADC TDM Swap Mux", "1/3/2/4", "IF1 ADC" },
{ "IF1 ADC TDM Swap Mux", "1/4/2/3", "IF1 ADC" },
{ "IF1 ADC TDM Swap Mux", "3/1/2/4", "IF1 ADC" },
{ "IF1 ADC TDM Swap Mux", "3/4/1/2", "IF1 ADC" },
{ "AIF1TX", NULL, "I2S1" },
{ "AIF1TX", NULL, "IF1 ADC1 Mux" },
{ "AIF1TX", NULL, "IF1 ADC2 Mux" },
{ "AIF1TX", NULL, "IF1 ADC3 Mux" },
{ "AIF1TX", NULL, "IF1 ADC4 Mux" },
{ "AIF1TX", NULL, "IF1 ADC TDM Swap Mux" },
{ "IF2 ADC1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" },
{ "IF2 ADC1 Mux", "OB01", "OB01 Bypass Mux" },
......@@ -2375,11 +3000,42 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "IF2 ADC4 Mux", "OB67", "OB67" },
{ "IF2 ADC4 Mux", "OB01", "OB01 Bypass Mux" },
{ "IF2 ADC1 Swap Mux", "L/R", "IF2 ADC1 Mux" },
{ "IF2 ADC1 Swap Mux", "R/L", "IF2 ADC1 Mux" },
{ "IF2 ADC1 Swap Mux", "L/L", "IF2 ADC1 Mux" },
{ "IF2 ADC1 Swap Mux", "R/R", "IF2 ADC1 Mux" },
{ "IF2 ADC2 Swap Mux", "L/R", "IF2 ADC2 Mux" },
{ "IF2 ADC2 Swap Mux", "R/L", "IF2 ADC2 Mux" },
{ "IF2 ADC2 Swap Mux", "L/L", "IF2 ADC2 Mux" },
{ "IF2 ADC2 Swap Mux", "R/R", "IF2 ADC2 Mux" },
{ "IF2 ADC3 Swap Mux", "L/R", "IF2 ADC3 Mux" },
{ "IF2 ADC3 Swap Mux", "R/L", "IF2 ADC3 Mux" },
{ "IF2 ADC3 Swap Mux", "L/L", "IF2 ADC3 Mux" },
{ "IF2 ADC3 Swap Mux", "R/R", "IF2 ADC3 Mux" },
{ "IF2 ADC4 Swap Mux", "L/R", "IF2 ADC4 Mux" },
{ "IF2 ADC4 Swap Mux", "R/L", "IF2 ADC4 Mux" },
{ "IF2 ADC4 Swap Mux", "L/L", "IF2 ADC4 Mux" },
{ "IF2 ADC4 Swap Mux", "R/R", "IF2 ADC4 Mux" },
{ "IF2 ADC", NULL, "IF2 ADC1 Swap Mux" },
{ "IF2 ADC", NULL, "IF2 ADC2 Swap Mux" },
{ "IF2 ADC", NULL, "IF2 ADC3 Swap Mux" },
{ "IF2 ADC", NULL, "IF2 ADC4 Swap Mux" },
{ "IF2 ADC TDM Swap Mux", "1/2/3/4", "IF2 ADC" },
{ "IF2 ADC TDM Swap Mux", "2/1/3/4", "IF2 ADC" },
{ "IF2 ADC TDM Swap Mux", "3/1/2/4", "IF2 ADC" },
{ "IF2 ADC TDM Swap Mux", "4/1/2/3", "IF2 ADC" },
{ "IF2 ADC TDM Swap Mux", "1/3/2/4", "IF2 ADC" },
{ "IF2 ADC TDM Swap Mux", "1/4/2/3", "IF2 ADC" },
{ "IF2 ADC TDM Swap Mux", "2/3/1/4", "IF2 ADC" },
{ "IF2 ADC TDM Swap Mux", "3/4/1/2", "IF2 ADC" },
{ "AIF2TX", NULL, "I2S2" },
{ "AIF2TX", NULL, "IF2 ADC1 Mux" },
{ "AIF2TX", NULL, "IF2 ADC2 Mux" },
{ "AIF2TX", NULL, "IF2 ADC3 Mux" },
{ "AIF2TX", NULL, "IF2 ADC4 Mux" },
{ "AIF2TX", NULL, "IF2 ADC TDM Swap Mux" },
{ "IF3 ADC Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" },
{ "IF3 ADC Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" },
......@@ -2569,14 +3225,86 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "IF1 DAC6", NULL, "I2S1" },
{ "IF1 DAC7", NULL, "I2S1" },
{ "IF1 DAC01", NULL, "IF1 DAC0" },
{ "IF1 DAC01", NULL, "IF1 DAC1" },
{ "IF1 DAC23", NULL, "IF1 DAC2" },
{ "IF1 DAC23", NULL, "IF1 DAC3" },
{ "IF1 DAC45", NULL, "IF1 DAC4" },
{ "IF1 DAC45", NULL, "IF1 DAC5" },
{ "IF1 DAC67", NULL, "IF1 DAC6" },
{ "IF1 DAC67", NULL, "IF1 DAC7" },
{ "IF1 DAC0 Mux", "Slot0", "IF1 DAC0" },
{ "IF1 DAC0 Mux", "Slot1", "IF1 DAC1" },
{ "IF1 DAC0 Mux", "Slot2", "IF1 DAC2" },
{ "IF1 DAC0 Mux", "Slot3", "IF1 DAC3" },
{ "IF1 DAC0 Mux", "Slot4", "IF1 DAC4" },
{ "IF1 DAC0 Mux", "Slot5", "IF1 DAC5" },
{ "IF1 DAC0 Mux", "Slot6", "IF1 DAC6" },
{ "IF1 DAC0 Mux", "Slot7", "IF1 DAC7" },
{ "IF1 DAC1 Mux", "Slot0", "IF1 DAC0" },
{ "IF1 DAC1 Mux", "Slot1", "IF1 DAC1" },
{ "IF1 DAC1 Mux", "Slot2", "IF1 DAC2" },
{ "IF1 DAC1 Mux", "Slot3", "IF1 DAC3" },
{ "IF1 DAC1 Mux", "Slot4", "IF1 DAC4" },
{ "IF1 DAC1 Mux", "Slot5", "IF1 DAC5" },
{ "IF1 DAC1 Mux", "Slot6", "IF1 DAC6" },
{ "IF1 DAC1 Mux", "Slot7", "IF1 DAC7" },
{ "IF1 DAC2 Mux", "Slot0", "IF1 DAC0" },
{ "IF1 DAC2 Mux", "Slot1", "IF1 DAC1" },
{ "IF1 DAC2 Mux", "Slot2", "IF1 DAC2" },
{ "IF1 DAC2 Mux", "Slot3", "IF1 DAC3" },
{ "IF1 DAC2 Mux", "Slot4", "IF1 DAC4" },
{ "IF1 DAC2 Mux", "Slot5", "IF1 DAC5" },
{ "IF1 DAC2 Mux", "Slot6", "IF1 DAC6" },
{ "IF1 DAC2 Mux", "Slot7", "IF1 DAC7" },
{ "IF1 DAC3 Mux", "Slot0", "IF1 DAC0" },
{ "IF1 DAC3 Mux", "Slot1", "IF1 DAC1" },
{ "IF1 DAC3 Mux", "Slot2", "IF1 DAC2" },
{ "IF1 DAC3 Mux", "Slot3", "IF1 DAC3" },
{ "IF1 DAC3 Mux", "Slot4", "IF1 DAC4" },
{ "IF1 DAC3 Mux", "Slot5", "IF1 DAC5" },
{ "IF1 DAC3 Mux", "Slot6", "IF1 DAC6" },
{ "IF1 DAC3 Mux", "Slot7", "IF1 DAC7" },
{ "IF1 DAC4 Mux", "Slot0", "IF1 DAC0" },
{ "IF1 DAC4 Mux", "Slot1", "IF1 DAC1" },
{ "IF1 DAC4 Mux", "Slot2", "IF1 DAC2" },
{ "IF1 DAC4 Mux", "Slot3", "IF1 DAC3" },
{ "IF1 DAC4 Mux", "Slot4", "IF1 DAC4" },
{ "IF1 DAC4 Mux", "Slot5", "IF1 DAC5" },
{ "IF1 DAC4 Mux", "Slot6", "IF1 DAC6" },
{ "IF1 DAC4 Mux", "Slot7", "IF1 DAC7" },
{ "IF1 DAC5 Mux", "Slot0", "IF1 DAC0" },
{ "IF1 DAC5 Mux", "Slot1", "IF1 DAC1" },
{ "IF1 DAC5 Mux", "Slot2", "IF1 DAC2" },
{ "IF1 DAC5 Mux", "Slot3", "IF1 DAC3" },
{ "IF1 DAC5 Mux", "Slot4", "IF1 DAC4" },
{ "IF1 DAC5 Mux", "Slot5", "IF1 DAC5" },
{ "IF1 DAC5 Mux", "Slot6", "IF1 DAC6" },
{ "IF1 DAC5 Mux", "Slot7", "IF1 DAC7" },
{ "IF1 DAC6 Mux", "Slot0", "IF1 DAC0" },
{ "IF1 DAC6 Mux", "Slot1", "IF1 DAC1" },
{ "IF1 DAC6 Mux", "Slot2", "IF1 DAC2" },
{ "IF1 DAC6 Mux", "Slot3", "IF1 DAC3" },
{ "IF1 DAC6 Mux", "Slot4", "IF1 DAC4" },
{ "IF1 DAC6 Mux", "Slot5", "IF1 DAC5" },
{ "IF1 DAC6 Mux", "Slot6", "IF1 DAC6" },
{ "IF1 DAC6 Mux", "Slot7", "IF1 DAC7" },
{ "IF1 DAC7 Mux", "Slot0", "IF1 DAC0" },
{ "IF1 DAC7 Mux", "Slot1", "IF1 DAC1" },
{ "IF1 DAC7 Mux", "Slot2", "IF1 DAC2" },
{ "IF1 DAC7 Mux", "Slot3", "IF1 DAC3" },
{ "IF1 DAC7 Mux", "Slot4", "IF1 DAC4" },
{ "IF1 DAC7 Mux", "Slot5", "IF1 DAC5" },
{ "IF1 DAC7 Mux", "Slot6", "IF1 DAC6" },
{ "IF1 DAC7 Mux", "Slot7", "IF1 DAC7" },
{ "IF1 DAC01", NULL, "IF1 DAC0 Mux" },
{ "IF1 DAC01", NULL, "IF1 DAC1 Mux" },
{ "IF1 DAC23", NULL, "IF1 DAC2 Mux" },
{ "IF1 DAC23", NULL, "IF1 DAC3 Mux" },
{ "IF1 DAC45", NULL, "IF1 DAC4 Mux" },
{ "IF1 DAC45", NULL, "IF1 DAC5 Mux" },
{ "IF1 DAC67", NULL, "IF1 DAC6 Mux" },
{ "IF1 DAC67", NULL, "IF1 DAC7 Mux" },
{ "IF2 DAC0", NULL, "AIF2RX" },
{ "IF2 DAC1", NULL, "AIF2RX" },
......@@ -2595,14 +3323,86 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "IF2 DAC6", NULL, "I2S2" },
{ "IF2 DAC7", NULL, "I2S2" },
{ "IF2 DAC01", NULL, "IF2 DAC0" },
{ "IF2 DAC01", NULL, "IF2 DAC1" },
{ "IF2 DAC23", NULL, "IF2 DAC2" },
{ "IF2 DAC23", NULL, "IF2 DAC3" },
{ "IF2 DAC45", NULL, "IF2 DAC4" },
{ "IF2 DAC45", NULL, "IF2 DAC5" },
{ "IF2 DAC67", NULL, "IF2 DAC6" },
{ "IF2 DAC67", NULL, "IF2 DAC7" },
{ "IF2 DAC0 Mux", "Slot0", "IF2 DAC0" },
{ "IF2 DAC0 Mux", "Slot1", "IF2 DAC1" },
{ "IF2 DAC0 Mux", "Slot2", "IF2 DAC2" },
{ "IF2 DAC0 Mux", "Slot3", "IF2 DAC3" },
{ "IF2 DAC0 Mux", "Slot4", "IF2 DAC4" },
{ "IF2 DAC0 Mux", "Slot5", "IF2 DAC5" },
{ "IF2 DAC0 Mux", "Slot6", "IF2 DAC6" },
{ "IF2 DAC0 Mux", "Slot7", "IF2 DAC7" },
{ "IF2 DAC1 Mux", "Slot0", "IF2 DAC0" },
{ "IF2 DAC1 Mux", "Slot1", "IF2 DAC1" },
{ "IF2 DAC1 Mux", "Slot2", "IF2 DAC2" },
{ "IF2 DAC1 Mux", "Slot3", "IF2 DAC3" },
{ "IF2 DAC1 Mux", "Slot4", "IF2 DAC4" },
{ "IF2 DAC1 Mux", "Slot5", "IF2 DAC5" },
{ "IF2 DAC1 Mux", "Slot6", "IF2 DAC6" },
{ "IF2 DAC1 Mux", "Slot7", "IF2 DAC7" },
{ "IF2 DAC2 Mux", "Slot0", "IF2 DAC0" },
{ "IF2 DAC2 Mux", "Slot1", "IF2 DAC1" },
{ "IF2 DAC2 Mux", "Slot2", "IF2 DAC2" },
{ "IF2 DAC2 Mux", "Slot3", "IF2 DAC3" },
{ "IF2 DAC2 Mux", "Slot4", "IF2 DAC4" },
{ "IF2 DAC2 Mux", "Slot5", "IF2 DAC5" },
{ "IF2 DAC2 Mux", "Slot6", "IF2 DAC6" },
{ "IF2 DAC2 Mux", "Slot7", "IF2 DAC7" },
{ "IF2 DAC3 Mux", "Slot0", "IF2 DAC0" },
{ "IF2 DAC3 Mux", "Slot1", "IF2 DAC1" },
{ "IF2 DAC3 Mux", "Slot2", "IF2 DAC2" },
{ "IF2 DAC3 Mux", "Slot3", "IF2 DAC3" },
{ "IF2 DAC3 Mux", "Slot4", "IF2 DAC4" },
{ "IF2 DAC3 Mux", "Slot5", "IF2 DAC5" },
{ "IF2 DAC3 Mux", "Slot6", "IF2 DAC6" },
{ "IF2 DAC3 Mux", "Slot7", "IF2 DAC7" },
{ "IF2 DAC4 Mux", "Slot0", "IF2 DAC0" },
{ "IF2 DAC4 Mux", "Slot1", "IF2 DAC1" },
{ "IF2 DAC4 Mux", "Slot2", "IF2 DAC2" },
{ "IF2 DAC4 Mux", "Slot3", "IF2 DAC3" },
{ "IF2 DAC4 Mux", "Slot4", "IF2 DAC4" },
{ "IF2 DAC4 Mux", "Slot5", "IF2 DAC5" },
{ "IF2 DAC4 Mux", "Slot6", "IF2 DAC6" },
{ "IF2 DAC4 Mux", "Slot7", "IF2 DAC7" },
{ "IF2 DAC5 Mux", "Slot0", "IF2 DAC0" },
{ "IF2 DAC5 Mux", "Slot1", "IF2 DAC1" },
{ "IF2 DAC5 Mux", "Slot2", "IF2 DAC2" },
{ "IF2 DAC5 Mux", "Slot3", "IF2 DAC3" },
{ "IF2 DAC5 Mux", "Slot4", "IF2 DAC4" },
{ "IF2 DAC5 Mux", "Slot5", "IF2 DAC5" },
{ "IF2 DAC5 Mux", "Slot6", "IF2 DAC6" },
{ "IF2 DAC5 Mux", "Slot7", "IF2 DAC7" },
{ "IF2 DAC6 Mux", "Slot0", "IF2 DAC0" },
{ "IF2 DAC6 Mux", "Slot1", "IF2 DAC1" },
{ "IF2 DAC6 Mux", "Slot2", "IF2 DAC2" },
{ "IF2 DAC6 Mux", "Slot3", "IF2 DAC3" },
{ "IF2 DAC6 Mux", "Slot4", "IF2 DAC4" },
{ "IF2 DAC6 Mux", "Slot5", "IF2 DAC5" },
{ "IF2 DAC6 Mux", "Slot6", "IF2 DAC6" },
{ "IF2 DAC6 Mux", "Slot7", "IF2 DAC7" },
{ "IF2 DAC7 Mux", "Slot0", "IF2 DAC0" },
{ "IF2 DAC7 Mux", "Slot1", "IF2 DAC1" },
{ "IF2 DAC7 Mux", "Slot2", "IF2 DAC2" },
{ "IF2 DAC7 Mux", "Slot3", "IF2 DAC3" },
{ "IF2 DAC7 Mux", "Slot4", "IF2 DAC4" },
{ "IF2 DAC7 Mux", "Slot5", "IF2 DAC5" },
{ "IF2 DAC7 Mux", "Slot6", "IF2 DAC6" },
{ "IF2 DAC7 Mux", "Slot7", "IF2 DAC7" },
{ "IF2 DAC01", NULL, "IF2 DAC0 Mux" },
{ "IF2 DAC01", NULL, "IF2 DAC1 Mux" },
{ "IF2 DAC23", NULL, "IF2 DAC2 Mux" },
{ "IF2 DAC23", NULL, "IF2 DAC3 Mux" },
{ "IF2 DAC45", NULL, "IF2 DAC4 Mux" },
{ "IF2 DAC45", NULL, "IF2 DAC5 Mux" },
{ "IF2 DAC67", NULL, "IF2 DAC6 Mux" },
{ "IF2 DAC67", NULL, "IF2 DAC7 Mux" },
{ "IF3 DAC", NULL, "AIF3RX" },
{ "IF3 DAC", NULL, "I2S3" },
......@@ -2806,9 +3606,13 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "LOUT2 amp", NULL, "DAC 2" },
{ "LOUT3 amp", NULL, "DAC 3" },
{ "LOUT1", NULL, "LOUT1 amp" },
{ "LOUT2", NULL, "LOUT2 amp" },
{ "LOUT3", NULL, "LOUT3 amp" },
{ "LOUT1 vref", NULL, "LOUT1 amp" },
{ "LOUT2 vref", NULL, "LOUT2 amp" },
{ "LOUT3 vref", NULL, "LOUT3 amp" },
{ "LOUT1", NULL, "LOUT1 vref" },
{ "LOUT2", NULL, "LOUT2 vref" },
{ "LOUT3", NULL, "LOUT3 vref" },
{ "PDM1L", NULL, "PDM1 L Mux" },
{ "PDM1R", NULL, "PDM1 R Mux" },
......@@ -2837,7 +3641,8 @@ static int rt5677_hw_params(struct snd_pcm_substream *substream,
rt5677->lrck[dai->id] = params_rate(params);
pre_div = rl6231_get_clk_info(rt5677->sysclk, rt5677->lrck[dai->id]);
if (pre_div < 0) {
dev_err(codec->dev, "Unsupported clock setting\n");
dev_err(codec->dev, "Unsupported clock setting: sysclk=%dHz lrck=%dHz\n",
rt5677->sysclk, rt5677->lrck[dai->id]);
return -EINVAL;
}
frame_size = snd_soc_params_to_frame_size(params);
......@@ -3181,6 +3986,8 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
rt5677_set_dsp_vad(codec, false);
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK,
0x0055);
......@@ -3188,14 +3995,12 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
RT5677_PR_BASE + RT5677_BIAS_CUR4,
0x0f00, 0x0f00);
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
RT5677_PWR_FV1 | RT5677_PWR_FV2 |
RT5677_PWR_VREF1 | RT5677_PWR_MB |
RT5677_PWR_BG | RT5677_PWR_VREF2,
RT5677_PWR_VREF1 | RT5677_PWR_MB |
RT5677_PWR_BG | RT5677_PWR_VREF2);
mdelay(20);
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
RT5677_PWR_FV1 | RT5677_PWR_FV2,
RT5677_PWR_FV1 | RT5677_PWR_FV2);
rt5677->is_vref_slow = false;
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
RT5677_PWR_CORE, RT5677_PWR_CORE);
regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC,
......@@ -3214,6 +4019,9 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000);
regmap_update_bits(rt5677->regmap,
RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000);
if (rt5677->dsp_vad_en)
rt5677_set_dsp_vad(codec, true);
break;
default:
......@@ -3309,6 +4117,78 @@ static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
return 0;
}
/** Configures the gpio as
* 0 - floating
* 1 - pull down
* 2 - pull up
*/
static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset,
int value)
{
int shift;
switch (offset) {
case RT5677_GPIO1 ... RT5677_GPIO2:
shift = 2 * (1 - offset);
regmap_update_bits(rt5677->regmap,
RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL2,
0x3 << shift,
(value & 0x3) << shift);
break;
case RT5677_GPIO3 ... RT5677_GPIO6:
shift = 2 * (9 - offset);
regmap_update_bits(rt5677->regmap,
RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL3,
0x3 << shift,
(value & 0x3) << shift);
break;
default:
break;
}
}
static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
struct regmap_irq_chip_data *data = rt5677->irq_data;
int irq;
if (offset >= RT5677_GPIO1 && offset <= RT5677_GPIO3) {
if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) ||
(rt5677->pdata.jd1_gpio == 2 &&
offset == RT5677_GPIO2) ||
(rt5677->pdata.jd1_gpio == 3 &&
offset == RT5677_GPIO3)) {
irq = RT5677_IRQ_JD1;
} else {
return -ENXIO;
}
}
if (offset >= RT5677_GPIO4 && offset <= RT5677_GPIO6) {
if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) ||
(rt5677->pdata.jd2_gpio == 2 &&
offset == RT5677_GPIO5) ||
(rt5677->pdata.jd2_gpio == 3 &&
offset == RT5677_GPIO6)) {
irq = RT5677_IRQ_JD2;
} else if ((rt5677->pdata.jd3_gpio == 1 &&
offset == RT5677_GPIO4) ||
(rt5677->pdata.jd3_gpio == 2 &&
offset == RT5677_GPIO5) ||
(rt5677->pdata.jd3_gpio == 3 &&
offset == RT5677_GPIO6)) {
irq = RT5677_IRQ_JD3;
} else {
return -ENXIO;
}
}
return regmap_irq_get_virq(data, irq);
}
static struct gpio_chip rt5677_template_chip = {
.label = "rt5677",
.owner = THIS_MODULE,
......@@ -3316,6 +4196,7 @@ static struct gpio_chip rt5677_template_chip = {
.set = rt5677_gpio_set,
.direction_input = rt5677_gpio_direction_in,
.get = rt5677_gpio_get,
.to_irq = rt5677_to_irq,
.can_sleep = 1,
};
......@@ -3341,6 +4222,11 @@ static void rt5677_free_gpio(struct i2c_client *i2c)
gpiochip_remove(&rt5677->gpio_chip);
}
#else
static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset,
int value)
{
}
static void rt5677_init_gpio(struct i2c_client *i2c)
{
}
......@@ -3353,6 +4239,7 @@ static void rt5677_free_gpio(struct i2c_client *i2c)
static int rt5677_probe(struct snd_soc_codec *codec)
{
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
int i;
rt5677->codec = codec;
......@@ -3371,6 +4258,37 @@ static int rt5677_probe(struct snd_soc_codec *codec)
regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020);
regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00);
for (i = 0; i < RT5677_GPIO_NUM; i++)
rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]);
if (rt5677->irq_data) {
regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, 0x8000,
0x8000);
regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x0018,
0x0008);
if (rt5677->pdata.jd1_gpio)
regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
RT5677_SEL_GPIO_JD1_MASK,
rt5677->pdata.jd1_gpio <<
RT5677_SEL_GPIO_JD1_SFT);
if (rt5677->pdata.jd2_gpio)
regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
RT5677_SEL_GPIO_JD2_MASK,
rt5677->pdata.jd2_gpio <<
RT5677_SEL_GPIO_JD2_SFT);
if (rt5677->pdata.jd3_gpio)
regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
RT5677_SEL_GPIO_JD3_MASK,
rt5677->pdata.jd3_gpio <<
RT5677_SEL_GPIO_JD3_SFT);
}
mutex_init(&rt5677->dsp_cmd_lock);
mutex_init(&rt5677->dsp_pri_lock);
return 0;
}
......@@ -3390,8 +4308,11 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
{
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
if (!rt5677->dsp_vad_en) {
regcache_cache_only(rt5677->regmap, true);
regcache_mark_dirty(rt5677->regmap);
}
if (gpio_is_valid(rt5677->pow_ldo2))
gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
......@@ -3406,8 +4327,11 @@ static int rt5677_resume(struct snd_soc_codec *codec)
gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
msleep(10);
}
if (!rt5677->dsp_vad_en) {
regcache_cache_only(rt5677->regmap, false);
regcache_sync(rt5677->regmap);
}
return 0;
}
......@@ -3416,6 +4340,51 @@ static int rt5677_resume(struct snd_soc_codec *codec)
#define rt5677_resume NULL
#endif
static int rt5677_read(void *context, unsigned int reg, unsigned int *val)
{
struct i2c_client *client = context;
struct rt5677_priv *rt5677 = i2c_get_clientdata(client);
if (rt5677->is_dsp_mode) {
if (reg > 0xff) {
mutex_lock(&rt5677->dsp_pri_lock);
rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
reg & 0xff);
rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val);
mutex_unlock(&rt5677->dsp_pri_lock);
} else {
rt5677_dsp_mode_i2c_read(rt5677, reg, val);
}
} else {
regmap_read(rt5677->regmap_physical, reg, val);
}
return 0;
}
static int rt5677_write(void *context, unsigned int reg, unsigned int val)
{
struct i2c_client *client = context;
struct rt5677_priv *rt5677 = i2c_get_clientdata(client);
if (rt5677->is_dsp_mode) {
if (reg > 0xff) {
mutex_lock(&rt5677->dsp_pri_lock);
rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
reg & 0xff);
rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA,
val);
mutex_unlock(&rt5677->dsp_pri_lock);
} else {
rt5677_dsp_mode_i2c_write(rt5677, reg, val);
}
} else {
regmap_write(rt5677->regmap_physical, reg, val);
}
return 0;
}
#define RT5677_STEREO_RATES SNDRV_PCM_RATE_8000_96000
#define RT5677_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
......@@ -3541,6 +4510,20 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5677 = {
.num_dapm_routes = ARRAY_SIZE(rt5677_dapm_routes),
};
static const struct regmap_config rt5677_regmap_physical = {
.name = "physical",
.reg_bits = 8,
.val_bits = 16,
.max_register = RT5677_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5677_ranges) *
RT5677_PR_SPACING),
.readable_reg = rt5677_readable_register,
.cache_type = REGCACHE_NONE,
.ranges = rt5677_ranges,
.num_ranges = ARRAY_SIZE(rt5677_ranges),
};
static const struct regmap_config rt5677_regmap = {
.reg_bits = 8,
.val_bits = 16,
......@@ -3550,6 +4533,8 @@ static const struct regmap_config rt5677_regmap = {
.volatile_reg = rt5677_volatile_register,
.readable_reg = rt5677_readable_register,
.reg_read = rt5677_read,
.reg_write = rt5677_write,
.cache_type = REGCACHE_RBTREE,
.reg_defaults = rt5677_reg,
......@@ -3590,7 +4575,75 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
(rt5677->pow_ldo2 != -ENOENT))
return rt5677->pow_ldo2;
of_property_read_u8_array(np, "realtek,gpio-config",
rt5677->pdata.gpio_config, RT5677_GPIO_NUM);
of_property_read_u32(np, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio);
of_property_read_u32(np, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio);
of_property_read_u32(np, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio);
return 0;
}
static struct regmap_irq rt5677_irqs[] = {
[RT5677_IRQ_JD1] = {
.reg_offset = 0,
.mask = RT5677_EN_IRQ_GPIO_JD1,
},
[RT5677_IRQ_JD2] = {
.reg_offset = 0,
.mask = RT5677_EN_IRQ_GPIO_JD2,
},
[RT5677_IRQ_JD3] = {
.reg_offset = 0,
.mask = RT5677_EN_IRQ_GPIO_JD3,
},
};
static struct regmap_irq_chip rt5677_irq_chip = {
.name = "rt5677",
.irqs = rt5677_irqs,
.num_irqs = ARRAY_SIZE(rt5677_irqs),
.num_regs = 1,
.status_base = RT5677_IRQ_CTRL1,
.mask_base = RT5677_IRQ_CTRL1,
.mask_invert = 1,
};
static int rt5677_init_irq(struct i2c_client *i2c)
{
int ret;
struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
if (!rt5677->pdata.jd1_gpio &&
!rt5677->pdata.jd2_gpio &&
!rt5677->pdata.jd3_gpio)
return 0;
if (!i2c->irq) {
dev_err(&i2c->dev, "No interrupt specified\n");
return -EINVAL;
}
ret = regmap_add_irq_chip(rt5677->regmap, i2c->irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
&rt5677_irq_chip, &rt5677->irq_data);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to register IRQ chip: %d\n", ret);
return ret;
}
return 0;
}
static void rt5677_free_irq(struct i2c_client *i2c)
{
struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
if (rt5677->irq_data)
regmap_del_irq_chip(i2c->irq, rt5677->irq_data);
}
static int rt5677_i2c_probe(struct i2c_client *i2c,
......@@ -3638,7 +4691,16 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
msleep(10);
}
rt5677->regmap = devm_regmap_init_i2c(i2c, &rt5677_regmap);
rt5677->regmap_physical = devm_regmap_init_i2c(i2c,
&rt5677_regmap_physical);
if (IS_ERR(rt5677->regmap_physical)) {
ret = PTR_ERR(rt5677->regmap_physical);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
ret);
return ret;
}
rt5677->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt5677_regmap);
if (IS_ERR(rt5677->regmap)) {
ret = PTR_ERR(rt5677->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
......@@ -3690,6 +4752,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
}
rt5677_init_gpio(i2c);
rt5677_init_irq(i2c);
return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677,
rt5677_dai, ARRAY_SIZE(rt5677_dai));
......@@ -3698,6 +4761,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
static int rt5677_i2c_remove(struct i2c_client *i2c)
{
snd_soc_unregister_codec(&i2c->dev);
rt5677_free_irq(i2c);
rt5677_free_gpio(i2c);
return 0;
......
......@@ -13,6 +13,7 @@
#define __RT5677_H__
#include <sound/rt5677.h>
#include <linux/gpio/driver.h>
/* Info */
#define RT5677_RESET 0x00
......@@ -305,10 +306,10 @@
#define RT5677_R_MUTE_SFT 7
#define RT5677_VOL_R_MUTE (0x1 << 6)
#define RT5677_VOL_R_SFT 6
#define RT5677_L_VOL_MASK (0x3f << 8)
#define RT5677_L_VOL_SFT 8
#define RT5677_R_VOL_MASK (0x3f)
#define RT5677_R_VOL_SFT 0
#define RT5677_L_VOL_MASK (0x7f << 9)
#define RT5677_L_VOL_SFT 9
#define RT5677_R_VOL_MASK (0x7f << 1)
#define RT5677_R_VOL_SFT 1
/* LOUT1 Control (0x01) */
#define RT5677_LOUT1_L_MUTE (0x1 << 15)
......@@ -446,16 +447,16 @@
#define RT5677_SEL_DAC2_R_SRC_SFT 0
/* Stereo1 ADC Digital Volume Control (0x1c) */
#define RT5677_STO1_ADC_L_VOL_MASK (0x7f << 8)
#define RT5677_STO1_ADC_L_VOL_SFT 8
#define RT5677_STO1_ADC_R_VOL_MASK (0x7f)
#define RT5677_STO1_ADC_R_VOL_SFT 0
#define RT5677_STO1_ADC_L_VOL_MASK (0x3f << 9)
#define RT5677_STO1_ADC_L_VOL_SFT 9
#define RT5677_STO1_ADC_R_VOL_MASK (0x3f << 1)
#define RT5677_STO1_ADC_R_VOL_SFT 1
/* Mono ADC Digital Volume Control (0x1d) */
#define RT5677_MONO_ADC_L_VOL_MASK (0x7f << 8)
#define RT5677_MONO_ADC_L_VOL_SFT 8
#define RT5677_MONO_ADC_R_VOL_MASK (0x7f)
#define RT5677_MONO_ADC_R_VOL_SFT 0
#define RT5677_MONO_ADC_L_VOL_MASK (0x3f << 9)
#define RT5677_MONO_ADC_L_VOL_SFT 9
#define RT5677_MONO_ADC_R_VOL_MASK (0x3f << 1)
#define RT5677_MONO_ADC_R_VOL_SFT 1
/* Stereo 1/2 ADC Boost Gain Control (0x1e) */
#define RT5677_STO1_ADC_L_BST_MASK (0x3 << 14)
......@@ -798,7 +799,21 @@
#define RT5677_PDM2_I2C_EXE (0x1 << 1)
#define RT5677_PDM2_I2C_BUSY (0x1 << 0)
/* MX3C TDM1 control 1 (0x3c) */
/* TDM1 control 1 (0x3b) */
#define RT5677_IF1_ADC_MODE_MASK (0x1 << 12)
#define RT5677_IF1_ADC_MODE_SFT 12
#define RT5677_IF1_ADC_MODE_I2S (0x0 << 12)
#define RT5677_IF1_ADC_MODE_TDM (0x1 << 12)
#define RT5677_IF1_ADC1_SWAP_MASK (0x3 << 6)
#define RT5677_IF1_ADC1_SWAP_SFT 6
#define RT5677_IF1_ADC2_SWAP_MASK (0x3 << 4)
#define RT5677_IF1_ADC2_SWAP_SFT 4
#define RT5677_IF1_ADC3_SWAP_MASK (0x3 << 2)
#define RT5677_IF1_ADC3_SWAP_SFT 2
#define RT5677_IF1_ADC4_SWAP_MASK (0x3 << 0)
#define RT5677_IF1_ADC4_SWAP_SFT 0
/* TDM1 control 2 (0x3c) */
#define RT5677_IF1_ADC4_MASK (0x3 << 10)
#define RT5677_IF1_ADC4_SFT 10
#define RT5677_IF1_ADC3_MASK (0x3 << 8)
......@@ -807,8 +822,44 @@
#define RT5677_IF1_ADC2_SFT 6
#define RT5677_IF1_ADC1_MASK (0x3 << 4)
#define RT5677_IF1_ADC1_SFT 4
/* MX41 TDM2 control 1 (0x41) */
#define RT5677_IF1_ADC_CTRL_MASK (0x7 << 0)
#define RT5677_IF1_ADC_CTRL_SFT 0
/* TDM1 control 4 (0x3e) */
#define RT5677_IF1_DAC0_MASK (0x7 << 12)
#define RT5677_IF1_DAC0_SFT 12
#define RT5677_IF1_DAC1_MASK (0x7 << 8)
#define RT5677_IF1_DAC1_SFT 8
#define RT5677_IF1_DAC2_MASK (0x7 << 4)
#define RT5677_IF1_DAC2_SFT 4
#define RT5677_IF1_DAC3_MASK (0x7 << 0)
#define RT5677_IF1_DAC3_SFT 0
/* TDM1 control 5 (0x3f) */
#define RT5677_IF1_DAC4_MASK (0x7 << 12)
#define RT5677_IF1_DAC4_SFT 12
#define RT5677_IF1_DAC5_MASK (0x7 << 8)
#define RT5677_IF1_DAC5_SFT 8
#define RT5677_IF1_DAC6_MASK (0x7 << 4)
#define RT5677_IF1_DAC6_SFT 4
#define RT5677_IF1_DAC7_MASK (0x7 << 0)
#define RT5677_IF1_DAC7_SFT 0
/* TDM2 control 1 (0x40) */
#define RT5677_IF2_ADC_MODE_MASK (0x1 << 12)
#define RT5677_IF2_ADC_MODE_SFT 12
#define RT5677_IF2_ADC_MODE_I2S (0x0 << 12)
#define RT5677_IF2_ADC_MODE_TDM (0x1 << 12)
#define RT5677_IF2_ADC1_SWAP_MASK (0x3 << 6)
#define RT5677_IF2_ADC1_SWAP_SFT 6
#define RT5677_IF2_ADC2_SWAP_MASK (0x3 << 4)
#define RT5677_IF2_ADC2_SWAP_SFT 4
#define RT5677_IF2_ADC3_SWAP_MASK (0x3 << 2)
#define RT5677_IF2_ADC3_SWAP_SFT 2
#define RT5677_IF2_ADC4_SWAP_MASK (0x3 << 0)
#define RT5677_IF2_ADC4_SWAP_SFT 0
/* TDM2 control 2 (0x41) */
#define RT5677_IF2_ADC4_MASK (0x3 << 10)
#define RT5677_IF2_ADC4_SFT 10
#define RT5677_IF2_ADC3_MASK (0x3 << 8)
......@@ -817,6 +868,28 @@
#define RT5677_IF2_ADC2_SFT 6
#define RT5677_IF2_ADC1_MASK (0x3 << 4)
#define RT5677_IF2_ADC1_SFT 4
#define RT5677_IF2_ADC_CTRL_MASK (0x7 << 0)
#define RT5677_IF2_ADC_CTRL_SFT 0
/* TDM2 control 4 (0x43) */
#define RT5677_IF2_DAC0_MASK (0x7 << 12)
#define RT5677_IF2_DAC0_SFT 12
#define RT5677_IF2_DAC1_MASK (0x7 << 8)
#define RT5677_IF2_DAC1_SFT 8
#define RT5677_IF2_DAC2_MASK (0x7 << 4)
#define RT5677_IF2_DAC2_SFT 4
#define RT5677_IF2_DAC3_MASK (0x7 << 0)
#define RT5677_IF2_DAC3_SFT 0
/* TDM2 control 5 (0x44) */
#define RT5677_IF2_DAC4_MASK (0x7 << 12)
#define RT5677_IF2_DAC4_SFT 12
#define RT5677_IF2_DAC5_MASK (0x7 << 8)
#define RT5677_IF2_DAC5_SFT 8
#define RT5677_IF2_DAC6_MASK (0x7 << 4)
#define RT5677_IF2_DAC6_SFT 4
#define RT5677_IF2_DAC7_MASK (0x7 << 0)
#define RT5677_IF2_DAC7_SFT 0
/* Digital Microphone Control 1 (0x50) */
#define RT5677_DMIC_1_EN_MASK (0x1 << 15)
......@@ -1367,6 +1440,48 @@
#define RT5677_SEL_SRC_IB01 (0x1 << 0)
#define RT5677_SEL_SRC_IB01_SFT 0
/* Jack Detect Control 1 (0xb5) */
#define RT5677_SEL_GPIO_JD1_MASK (0x3 << 14)
#define RT5677_SEL_GPIO_JD1_SFT 14
#define RT5677_SEL_GPIO_JD2_MASK (0x3 << 12)
#define RT5677_SEL_GPIO_JD2_SFT 12
#define RT5677_SEL_GPIO_JD3_MASK (0x3 << 10)
#define RT5677_SEL_GPIO_JD3_SFT 10
/* IRQ Control 1 (0xbd) */
#define RT5677_STA_GPIO_JD1 (0x1 << 15)
#define RT5677_STA_GPIO_JD1_SFT 15
#define RT5677_EN_IRQ_GPIO_JD1 (0x1 << 14)
#define RT5677_EN_IRQ_GPIO_JD1_SFT 14
#define RT5677_EN_GPIO_JD1_STICKY (0x1 << 13)
#define RT5677_EN_GPIO_JD1_STICKY_SFT 13
#define RT5677_INV_GPIO_JD1 (0x1 << 12)
#define RT5677_INV_GPIO_JD1_SFT 12
#define RT5677_STA_GPIO_JD2 (0x1 << 11)
#define RT5677_STA_GPIO_JD2_SFT 11
#define RT5677_EN_IRQ_GPIO_JD2 (0x1 << 10)
#define RT5677_EN_IRQ_GPIO_JD2_SFT 10
#define RT5677_EN_GPIO_JD2_STICKY (0x1 << 9)
#define RT5677_EN_GPIO_JD2_STICKY_SFT 9
#define RT5677_INV_GPIO_JD2 (0x1 << 8)
#define RT5677_INV_GPIO_JD2_SFT 8
#define RT5677_STA_MICBIAS1_OVCD (0x1 << 7)
#define RT5677_STA_MICBIAS1_OVCD_SFT 7
#define RT5677_EN_IRQ_MICBIAS1_OVCD (0x1 << 6)
#define RT5677_EN_IRQ_MICBIAS1_OVCD_SFT 6
#define RT5677_EN_MICBIAS1_OVCD_STICKY (0x1 << 5)
#define RT5677_EN_MICBIAS1_OVCD_STICKY_SFT 5
#define RT5677_INV_MICBIAS1_OVCD (0x1 << 4)
#define RT5677_INV_MICBIAS1_OVCD_SFT 4
#define RT5677_STA_GPIO_JD3 (0x1 << 3)
#define RT5677_STA_GPIO_JD3_SFT 3
#define RT5677_EN_IRQ_GPIO_JD3 (0x1 << 2)
#define RT5677_EN_IRQ_GPIO_JD3_SFT 2
#define RT5677_EN_GPIO_JD3_STICKY (0x1 << 1)
#define RT5677_EN_GPIO_JD3_STICKY_SFT 1
#define RT5677_INV_GPIO_JD3 (0x1 << 0)
#define RT5677_INV_GPIO_JD3_SFT 0
/* GPIO status (0xbf) */
#define RT5677_GPIO6_STATUS_MASK (0x1 << 5)
#define RT5677_GPIO6_STATUS_SFT 5
......@@ -1506,6 +1621,9 @@
#define RT5677_GPIO5_FUNC_GPIO (0x0 << 9)
#define RT5677_GPIO5_FUNC_DMIC (0x1 << 9)
#define RT5677_FIRMWARE1 "rt5677_dsp_fw1.bin"
#define RT5677_FIRMWARE2 "rt5677_dsp_fw2.bin"
/* System Clock Source */
enum {
RT5677_SCLK_S_MCLK,
......@@ -1541,10 +1659,18 @@ enum {
RT5677_GPIO_NUM,
};
enum {
RT5677_IRQ_JD1,
RT5677_IRQ_JD2,
RT5677_IRQ_JD3,
};
struct rt5677_priv {
struct snd_soc_codec *codec;
struct rt5677_platform_data pdata;
struct regmap *regmap;
struct regmap *regmap, *regmap_physical;
const struct firmware *fw1, *fw2;
struct mutex dsp_cmd_lock, dsp_pri_lock;
int sysclk;
int sysclk_src;
......@@ -1558,6 +1684,10 @@ struct rt5677_priv {
#ifdef CONFIG_GPIOLIB
struct gpio_chip gpio_chip;
#endif
bool dsp_vad_en;
struct regmap_irq_chip_data *irq_data;
bool is_dsp_mode;
bool is_vref_slow;
};
#endif /* __RT5677_H__ */
......@@ -16,6 +16,7 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/clk.h>
#include <linux/log2.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
......@@ -121,6 +122,13 @@ struct ldo_regulator {
bool enabled;
};
enum sgtl5000_micbias_resistor {
SGTL5000_MICBIAS_OFF = 0,
SGTL5000_MICBIAS_2K = 2,
SGTL5000_MICBIAS_4K = 4,
SGTL5000_MICBIAS_8K = 8,
};
/* sgtl5000 private structure in codec */
struct sgtl5000_priv {
int sysclk; /* sysclk rate */
......@@ -131,6 +139,8 @@ struct sgtl5000_priv {
struct regmap *regmap;
struct clk *mclk;
int revision;
u8 micbias_resistor;
u8 micbias_voltage;
};
/*
......@@ -145,12 +155,14 @@ struct sgtl5000_priv {
static int mic_bias_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(w->codec);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
/* change mic bias resistor to 4Kohm */
/* change mic bias resistor */
snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
SGTL5000_BIAS_R_MASK,
SGTL5000_BIAS_R_4k << SGTL5000_BIAS_R_SHIFT);
sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT);
break;
case SND_SOC_DAPM_PRE_PMD:
......@@ -530,16 +542,16 @@ static int sgtl5000_set_dai_sysclk(struct snd_soc_dai *codec_dai,
/*
* set clock according to i2s frame clock,
* sgtl5000 provide 2 clock sources.
* 1. sys_mclk. sample freq can only configure to
* sgtl5000 provides 2 clock sources:
* 1. sys_mclk: sample freq can only be configured to
* 1/256, 1/384, 1/512 of sys_mclk.
* 2. pll. can derive any audio clocks.
* 2. pll: can derive any audio clocks.
*
* clock setting rules:
* 1. in slave mode, only sys_mclk can use.
* 2. as constraint by sys_mclk, sample freq should
* set to 32k, 44.1k and above.
* 3. using sys_mclk prefer to pll to save power.
* 1. in slave mode, only sys_mclk can be used
* 2. as constraint by sys_mclk, sample freq should be set to 32 kHz, 44.1 kHz
* and above.
* 3. usage of sys_mclk is preferred over pll to save power.
*/
static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
{
......@@ -549,8 +561,8 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
/*
* sample freq should be divided by frame clock,
* if frame clock lower than 44.1khz, sample feq should set to
* 32khz or 44.1khz.
* if frame clock is lower than 44.1 kHz, sample freq should be set to
* 32 kHz or 44.1 kHz.
*/
switch (frame_rate) {
case 8000:
......@@ -603,9 +615,10 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
/*
* calculate the divider of mclk/sample_freq,
* factor of freq =96k can only be 256, since mclk in range (12m,27m)
* factor of freq = 96 kHz can only be 256, since mclk is in the range
* of 8 MHz - 27 MHz
*/
switch (sgtl5000->sysclk / sys_fs) {
switch (sgtl5000->sysclk / frame_rate) {
case 256:
clk_ctl |= SGTL5000_MCLK_FREQ_256FS <<
SGTL5000_MCLK_FREQ_SHIFT;
......@@ -619,7 +632,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
SGTL5000_MCLK_FREQ_SHIFT;
break;
default:
/* if mclk not satisify the divider, use pll */
/* if mclk does not satisfy the divider, use pll */
if (sgtl5000->master) {
clk_ctl |= SGTL5000_MCLK_FREQ_PLL <<
SGTL5000_MCLK_FREQ_SHIFT;
......@@ -628,7 +641,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
"PLL not supported in slave mode\n");
dev_err(codec->dev, "%d ratio is not supported. "
"SYS_MCLK needs to be 256, 384 or 512 * fs\n",
sgtl5000->sysclk / sys_fs);
sgtl5000->sysclk / frame_rate);
return -EINVAL;
}
}
......@@ -795,7 +808,7 @@ static int ldo_regulator_enable(struct regulator_dev *dev)
SGTL5000_LINEREG_D_POWERUP,
SGTL5000_LINEREG_D_POWERUP);
/* when internal ldo enabled, simple digital power can be disabled */
/* when internal ldo is enabled, simple digital power can be disabled */
snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
SGTL5000_LINREG_SIMPLE_POWERUP,
0);
......@@ -1079,7 +1092,7 @@ static bool sgtl5000_readable(struct device *dev, unsigned int reg)
/*
* sgtl5000 has 3 internal power supplies:
* 1. VAG, normally set to vdda/2
* 2. chargepump, set to different value
* 2. charge pump, set to different value
* according to voltage of vdda and vddio
* 3. line out VAG, normally set to vddio/2
*
......@@ -1325,8 +1338,13 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
SGTL5000_HP_ZCD_EN |
SGTL5000_ADC_ZCD_EN);
snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 2);
snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
SGTL5000_BIAS_R_MASK,
sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT);
snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
SGTL5000_BIAS_R_MASK,
sgtl5000->micbias_voltage << SGTL5000_BIAS_R_SHIFT);
/*
* disable DAP
* TODO:
......@@ -1416,10 +1434,10 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
{
struct sgtl5000_priv *sgtl5000;
int ret, reg, rev;
unsigned int mclk;
struct device_node *np = client->dev.of_node;
u32 value;
sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv),
GFP_KERNEL);
sgtl5000 = devm_kzalloc(&client->dev, sizeof(*sgtl5000), GFP_KERNEL);
if (!sgtl5000)
return -ENOMEM;
......@@ -1440,14 +1458,6 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
return ret;
}
/* SGTL5000 SYS_MCLK should be between 8 and 27 MHz */
mclk = clk_get_rate(sgtl5000->mclk);
if (mclk < 8000000 || mclk > 27000000) {
dev_err(&client->dev, "Invalid SYS_CLK frequency: %u.%03uMHz\n",
mclk / 1000000, mclk / 1000 % 1000);
return -EINVAL;
}
ret = clk_prepare_enable(sgtl5000->mclk);
if (ret)
return ret;
......@@ -1469,6 +1479,47 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev);
sgtl5000->revision = rev;
if (np) {
if (!of_property_read_u32(np,
"micbias-resistor-k-ohms", &value)) {
switch (value) {
case SGTL5000_MICBIAS_OFF:
sgtl5000->micbias_resistor = 0;
break;
case SGTL5000_MICBIAS_2K:
sgtl5000->micbias_resistor = 1;
break;
case SGTL5000_MICBIAS_4K:
sgtl5000->micbias_resistor = 2;
break;
case SGTL5000_MICBIAS_8K:
sgtl5000->micbias_resistor = 3;
break;
default:
sgtl5000->micbias_resistor = 2;
dev_err(&client->dev,
"Unsuitable MicBias resistor\n");
}
} else {
/* default is 4Kohms */
sgtl5000->micbias_resistor = 2;
}
if (!of_property_read_u32(np,
"micbias-voltage-m-volts", &value)) {
/* 1250mV => 0 */
/* steps of 250mV */
if ((value >= 1250) && (value <= 3000))
sgtl5000->micbias_voltage = (value / 250) - 5;
else {
sgtl5000->micbias_voltage = 0;
dev_err(&client->dev,
"Unsuitable MicBias resistor\n");
}
} else {
sgtl5000->micbias_voltage = 0;
}
}
i2c_set_clientdata(client, sgtl5000);
/* Ensure sgtl5000 will start with sane register values */
......
config SND_SOC_SAMSUNG
tristate "ASoC support for Samsung"
depends on PLAT_SAMSUNG
depends on (PLAT_SAMSUNG || ARCH_EXYNOS)
depends on S3C64XX_PL080 || !ARCH_S3C64XX
depends on S3C24XX_DMAC || !ARCH_S3C24XX
select SND_SOC_GENERIC_DMAENGINE_PCM
......@@ -239,3 +239,9 @@ config SND_SOC_ODROIDX2
select SND_SAMSUNG_I2S
help
Say Y here to enable audio support for the Odroid-X2/U3.
config SND_SOC_ARNDALE_RT5631_ALC5631
tristate "Audio support for RT5631(ALC5631) on Arndale Board"
depends on SND_SOC_SAMSUNG
select SND_SAMSUNG_I2S
select SND_SOC_RT5631
......@@ -45,6 +45,7 @@ snd-soc-lowland-objs := lowland.o
snd-soc-littlemill-objs := littlemill.o
snd-soc-bells-objs := bells.o
snd-soc-odroidx2-max98090-objs := odroidx2_max98090.o
snd-soc-arndale-rt5631-objs := arndale_rt5631.o
obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
......@@ -71,3 +72,4 @@ obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o
obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o
obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o
obj-$(CONFIG_SND_SOC_ODROIDX2) += snd-soc-odroidx2-max98090.o
obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o
/*
* arndale_rt5631.c
*
* Copyright (c) 2014, Insignal Co., Ltd.
*
* Author: Claude <claude@insginal.co.kr>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include "i2s.h"
static int arndale_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;
int rfs, ret;
unsigned long rclk;
rfs = 256;
rclk = params_rate(params) * rfs;
ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,
0, SND_SOC_CLOCK_OUT);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
0, SND_SOC_CLOCK_OUT);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk, SND_SOC_CLOCK_OUT);
if (ret < 0)
return ret;
return 0;
}
static struct snd_soc_ops arndale_ops = {
.hw_params = arndale_hw_params,
};
static struct snd_soc_dai_link arndale_rt5631_dai[] = {
{
.name = "RT5631 HiFi",
.stream_name = "Primary",
.codec_dai_name = "rt5631-hifi",
.dai_fmt = SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS,
.ops = &arndale_ops,
},
};
static struct snd_soc_card arndale_rt5631 = {
.name = "Arndale RT5631",
.dai_link = arndale_rt5631_dai,
.num_links = ARRAY_SIZE(arndale_rt5631_dai),
};
static int arndale_audio_probe(struct platform_device *pdev)
{
int n, ret;
struct device_node *np = pdev->dev.of_node;
struct snd_soc_card *card = &arndale_rt5631;
card->dev = &pdev->dev;
for (n = 0; np && n < ARRAY_SIZE(arndale_rt5631_dai); n++) {
if (!arndale_rt5631_dai[n].cpu_dai_name) {
arndale_rt5631_dai[n].cpu_of_node = of_parse_phandle(np,
"samsung,audio-cpu", n);
if (!arndale_rt5631_dai[n].cpu_of_node) {
dev_err(&pdev->dev,
"Property 'samsung,audio-cpu' missing or invalid\n");
return -EINVAL;
}
}
if (!arndale_rt5631_dai[n].platform_name)
arndale_rt5631_dai[n].platform_of_node =
arndale_rt5631_dai[n].cpu_of_node;
arndale_rt5631_dai[n].codec_name = NULL;
arndale_rt5631_dai[n].codec_of_node = of_parse_phandle(np,
"samsung,audio-codec", n);
if (!arndale_rt5631_dai[0].codec_of_node) {
dev_err(&pdev->dev,
"Property 'samsung,audio-codec' missing or invalid\n");
return -EINVAL;
}
}
ret = devm_snd_soc_register_card(card->dev, card);
if (ret)
dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
return ret;
}
static int arndale_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = {
{ .compatible = "samsung,arndale-rt5631", },
{ .compatible = "samsung,arndale-alc5631", },
{},
};
MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match);
static struct platform_driver arndale_audio_driver = {
.driver = {
.name = "arndale-audio",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match),
},
.probe = arndale_audio_probe,
.remove = arndale_audio_remove,
};
module_platform_driver(arndale_audio_driver);
MODULE_AUTHOR("Claude <claude@insignal.co.kr>");
MODULE_DESCRIPTION("ALSA SoC Driver for Arndale Board");
MODULE_LICENSE("GPL");
......@@ -33,8 +33,9 @@
#define I2SLVL3ADDR 0x3c
#define I2SSTR1 0x40
#define I2SVER 0x44
#define I2SFIC2 0x48
#define I2SFIC1 0x48
#define I2STDM 0x4c
#define I2SFSTA 0x50
#define CON_RSTCLR (1 << 31)
#define CON_FRXOFSTATUS (1 << 26)
......@@ -93,8 +94,6 @@
#define MOD_BLC_24BIT (2 << 13)
#define MOD_BLC_MASK (3 << 13)
#define MOD_IMS_SYSMUX (1 << 10)
#define MOD_SLAVE (1 << 11)
#define MOD_TXONLY (0 << 8)
#define MOD_RXONLY (1 << 8)
#define MOD_TXRX (2 << 8)
......@@ -132,7 +131,10 @@
#define EXYNOS5420_MOD_BCLK_256FS 8
#define EXYNOS5420_MOD_BCLK_MASK 0xf
#define MOD_CDCLKCON (1 << 12)
#define EXYNOS7_MOD_RCLK_64FS 4
#define EXYNOS7_MOD_RCLK_128FS 5
#define EXYNOS7_MOD_RCLK_96FS 6
#define EXYNOS7_MOD_RCLK_192FS 7
#define PSR_PSREN (1 << 15)
......
......@@ -36,9 +36,24 @@ enum samsung_dai_type {
TYPE_SEC,
};
struct samsung_i2s_variant_regs {
unsigned int bfs_off;
unsigned int rfs_off;
unsigned int sdf_off;
unsigned int txr_off;
unsigned int rclksrc_off;
unsigned int mss_off;
unsigned int cdclkcon_off;
unsigned int lrp_off;
unsigned int bfs_mask;
unsigned int rfs_mask;
unsigned int ftx0cnt_off;
};
struct samsung_i2s_dai_data {
int dai_type;
u32 quirks;
const struct samsung_i2s_variant_regs *i2s_variant_regs;
};
struct i2s_dai {
......@@ -81,6 +96,7 @@ struct i2s_dai {
u32 suspend_i2scon;
u32 suspend_i2spsr;
unsigned long gpios[7]; /* i2s gpio line numbers */
const struct samsung_i2s_variant_regs *variant_regs;
};
/* Lock for cross i/f checks */
......@@ -95,7 +111,8 @@ static inline bool is_secondary(struct i2s_dai *i2s)
/* If operating in SoC-Slave mode */
static inline bool is_slave(struct i2s_dai *i2s)
{
return (readl(i2s->addr + I2SMOD) & MOD_SLAVE) ? true : false;
u32 mod = readl(i2s->addr + I2SMOD);
return (mod & (1 << i2s->variant_regs->mss_off)) ? true : false;
}
/* If this interface of the controller is transmitting data */
......@@ -200,14 +217,14 @@ static inline bool is_manager(struct i2s_dai *i2s)
static inline unsigned get_rfs(struct i2s_dai *i2s)
{
u32 rfs;
if (i2s->quirks & QUIRK_SUPPORTS_TDM)
rfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_RCLK_SHIFT;
else
rfs = (readl(i2s->addr + I2SMOD) >> MOD_RCLK_SHIFT);
rfs &= MOD_RCLK_MASK;
rfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->rfs_off;
rfs &= i2s->variant_regs->rfs_mask;
switch (rfs) {
case 7: return 192;
case 6: return 96;
case 5: return 128;
case 4: return 64;
case 3: return 768;
case 2: return 384;
case 1: return 512;
......@@ -219,15 +236,23 @@ static inline unsigned get_rfs(struct i2s_dai *i2s)
static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
{
u32 mod = readl(i2s->addr + I2SMOD);
int rfs_shift;
int rfs_shift = i2s->variant_regs->rfs_off;
if (i2s->quirks & QUIRK_SUPPORTS_TDM)
rfs_shift = EXYNOS5420_MOD_RCLK_SHIFT;
else
rfs_shift = MOD_RCLK_SHIFT;
mod &= ~(MOD_RCLK_MASK << rfs_shift);
mod &= ~(i2s->variant_regs->rfs_mask << rfs_shift);
switch (rfs) {
case 192:
mod |= (EXYNOS7_MOD_RCLK_192FS << rfs_shift);
break;
case 96:
mod |= (EXYNOS7_MOD_RCLK_96FS << rfs_shift);
break;
case 128:
mod |= (EXYNOS7_MOD_RCLK_128FS << rfs_shift);
break;
case 64:
mod |= (EXYNOS7_MOD_RCLK_64FS << rfs_shift);
break;
case 768:
mod |= (MOD_RCLK_768FS << rfs_shift);
break;
......@@ -249,14 +274,8 @@ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
static inline unsigned get_bfs(struct i2s_dai *i2s)
{
u32 bfs;
if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
bfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_BCLK_SHIFT;
bfs &= EXYNOS5420_MOD_BCLK_MASK;
} else {
bfs = readl(i2s->addr + I2SMOD) >> MOD_BCLK_SHIFT;
bfs &= MOD_BCLK_MASK;
}
bfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->bfs_off;
bfs &= i2s->variant_regs->bfs_mask;
switch (bfs) {
case 8: return 256;
......@@ -275,16 +294,8 @@ static inline unsigned get_bfs(struct i2s_dai *i2s)
static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
{
u32 mod = readl(i2s->addr + I2SMOD);
int bfs_shift;
int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM;
if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
bfs_shift = EXYNOS5420_MOD_BCLK_SHIFT;
mod &= ~(EXYNOS5420_MOD_BCLK_MASK << bfs_shift);
} else {
bfs_shift = MOD_BCLK_SHIFT;
mod &= ~(MOD_BCLK_MASK << bfs_shift);
}
int bfs_shift = i2s->variant_regs->bfs_off;
/* Non-TDM I2S controllers do not support BCLK > 48 * FS */
if (!tdm && bfs > 48) {
......@@ -292,6 +303,8 @@ static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
return;
}
mod &= ~(i2s->variant_regs->bfs_mask << bfs_shift);
switch (bfs) {
case 48:
mod |= (MOD_BCLK_48FS << bfs_shift);
......@@ -346,8 +359,9 @@ static inline int get_blc(struct i2s_dai *i2s)
static void i2s_txctrl(struct i2s_dai *i2s, int on)
{
void __iomem *addr = i2s->addr;
int txr_off = i2s->variant_regs->txr_off;
u32 con = readl(addr + I2SCON);
u32 mod = readl(addr + I2SMOD) & ~MOD_MASK;
u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off);
if (on) {
con |= CON_ACTIVE;
......@@ -362,9 +376,9 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on)
}
if (any_rx_active(i2s))
mod |= MOD_TXRX;
mod |= 2 << txr_off;
else
mod |= MOD_TXONLY;
mod |= 0 << txr_off;
} else {
if (is_secondary(i2s)) {
con |= CON_TXSDMA_PAUSE;
......@@ -382,7 +396,7 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on)
con |= CON_TXCH_PAUSE;
if (any_rx_active(i2s))
mod |= MOD_RXONLY;
mod |= 1 << txr_off;
else
con &= ~CON_ACTIVE;
}
......@@ -395,23 +409,24 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on)
static void i2s_rxctrl(struct i2s_dai *i2s, int on)
{
void __iomem *addr = i2s->addr;
int txr_off = i2s->variant_regs->txr_off;
u32 con = readl(addr + I2SCON);
u32 mod = readl(addr + I2SMOD) & ~MOD_MASK;
u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off);
if (on) {
con |= CON_RXDMA_ACTIVE | CON_ACTIVE;
con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE);
if (any_tx_active(i2s))
mod |= MOD_TXRX;
mod |= 2 << txr_off;
else
mod |= MOD_RXONLY;
mod |= 1 << txr_off;
} else {
con |= CON_RXDMA_PAUSE | CON_RXCH_PAUSE;
con &= ~CON_RXDMA_ACTIVE;
if (any_tx_active(i2s))
mod |= MOD_TXONLY;
mod |= 0 << txr_off;
else
con &= ~CON_ACTIVE;
}
......@@ -451,6 +466,9 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
struct i2s_dai *i2s = to_info(dai);
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
u32 mod = readl(i2s->addr + I2SMOD);
const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off;
unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off;
switch (clk_id) {
case SAMSUNG_I2S_OPCLK:
......@@ -465,18 +483,18 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
if ((rfs && other && other->rfs && (other->rfs != rfs)) ||
(any_active(i2s) &&
(((dir == SND_SOC_CLOCK_IN)
&& !(mod & MOD_CDCLKCON)) ||
&& !(mod & cdcon_mask)) ||
((dir == SND_SOC_CLOCK_OUT)
&& (mod & MOD_CDCLKCON))))) {
&& (mod & cdcon_mask))))) {
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
return -EAGAIN;
}
if (dir == SND_SOC_CLOCK_IN)
mod |= MOD_CDCLKCON;
mod |= 1 << i2s_regs->cdclkcon_off;
else
mod &= ~MOD_CDCLKCON;
mod &= ~(1 << i2s_regs->cdclkcon_off);
i2s->rfs = rfs;
break;
......@@ -491,8 +509,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
if (!any_active(i2s)) {
if (i2s->op_clk && !IS_ERR(i2s->op_clk)) {
if ((clk_id && !(mod & MOD_IMS_SYSMUX)) ||
(!clk_id && (mod & MOD_IMS_SYSMUX))) {
if ((clk_id && !(mod & rsrc_mask)) ||
(!clk_id && (mod & rsrc_mask))) {
clk_disable_unprepare(i2s->op_clk);
clk_put(i2s->op_clk);
} else {
......@@ -520,8 +538,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
other->op_clk = i2s->op_clk;
other->rclk_srcrate = i2s->rclk_srcrate;
}
} else if ((!clk_id && (mod & MOD_IMS_SYSMUX))
|| (clk_id && !(mod & MOD_IMS_SYSMUX))) {
} else if ((!clk_id && (mod & rsrc_mask))
|| (clk_id && !(mod & rsrc_mask))) {
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
return -EAGAIN;
......@@ -533,11 +551,11 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
}
if (clk_id == 0)
mod &= ~MOD_IMS_SYSMUX;
mod &= ~(1 << i2s_regs->rclksrc_off);
else
mod |= MOD_IMS_SYSMUX;
break;
mod |= 1 << i2s_regs->rclksrc_off;
break;
default:
dev_err(&i2s->pdev->dev, "We don't serve that!\n");
return -EINVAL;
......@@ -553,16 +571,12 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
{
struct i2s_dai *i2s = to_info(dai);
u32 mod = readl(i2s->addr + I2SMOD);
int lrp_shift, sdf_shift, sdf_mask, lrp_rlow;
int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave;
u32 tmp = 0;
if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
lrp_shift = EXYNOS5420_MOD_LRP_SHIFT;
sdf_shift = EXYNOS5420_MOD_SDF_SHIFT;
} else {
lrp_shift = MOD_LRP_SHIFT;
sdf_shift = MOD_SDF_SHIFT;
}
lrp_shift = i2s->variant_regs->lrp_off;
sdf_shift = i2s->variant_regs->sdf_off;
mod_slave = 1 << i2s->variant_regs->mss_off;
sdf_mask = MOD_SDF_MASK << sdf_shift;
lrp_rlow = MOD_LR_RLOW << lrp_shift;
......@@ -605,7 +619,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
tmp |= MOD_SLAVE;
tmp |= mod_slave;
break;
case SND_SOC_DAIFMT_CBS_CFS:
/* Set default source clock in Master mode */
......@@ -623,13 +637,13 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
* channel.
*/
if (any_active(i2s) &&
((mod & (sdf_mask | lrp_rlow | MOD_SLAVE)) != tmp)) {
((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) {
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
return -EAGAIN;
}
mod &= ~(sdf_mask | lrp_rlow | MOD_SLAVE);
mod &= ~(sdf_mask | lrp_rlow | mod_slave);
mod |= tmp;
writel(mod, i2s->addr + I2SMOD);
......@@ -751,6 +765,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream,
struct i2s_dai *i2s = to_info(dai);
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
unsigned long flags;
const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
spin_lock_irqsave(&lock, flags);
......@@ -761,7 +776,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream,
other->mode |= DAI_MANAGER;
} else {
u32 mod = readl(i2s->addr + I2SMOD);
i2s->cdclk_out = !(mod & MOD_CDCLKCON);
i2s->cdclk_out = !(mod & (1 << i2s_regs->cdclkcon_off));
if (other)
other->cdclk_out = i2s->cdclk_out;
}
......@@ -914,13 +929,14 @@ i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
struct i2s_dai *i2s = to_info(dai);
u32 reg = readl(i2s->addr + I2SFIC);
snd_pcm_sframes_t delay;
const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
delay = FIC_RXCOUNT(reg);
else if (is_secondary(i2s))
delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS));
else
delay = FIC_TXCOUNT(reg);
delay = (reg >> i2s_regs->ftx0cnt_off) & 0x7f;
return delay;
}
......@@ -956,6 +972,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct i2s_dai *i2s = to_info(dai);
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
int ret;
if (other && other->clk) { /* If this is probe on secondary */
samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback,
......@@ -973,9 +990,14 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
if (IS_ERR(i2s->clk)) {
dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n");
iounmap(i2s->addr);
return -ENOENT;
return PTR_ERR(i2s->clk);
}
ret = clk_prepare_enable(i2s->clk);
if (ret != 0) {
dev_err(&i2s->pdev->dev, "failed to enable clock: %d\n", ret);
return ret;
}
clk_prepare_enable(i2s->clk);
samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
......@@ -987,7 +1009,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
if (i2s->quirks & QUIRK_NEED_RSTCLR)
writel(CON_RSTCLR, i2s->addr + I2SCON);
if (i2s->quirks & QUIRK_SEC_DAI)
if (i2s->quirks & QUIRK_SUPPORTS_IDMA)
idma_reg_addr_init(i2s->addr,
i2s->sec_dai->idma_playback.dma_addr);
......@@ -1199,10 +1221,9 @@ static int samsung_i2s_probe(struct platform_device *pdev)
quirks = i2s_dai_data->quirks;
if (of_property_read_u32(np, "samsung,idma-addr",
&idma_addr)) {
if (quirks & QUIRK_SEC_DAI) {
dev_err(&pdev->dev, "idma address is not"\
if (quirks & QUIRK_SUPPORTS_IDMA) {
dev_info(&pdev->dev, "idma address is not"\
"specified");
return -EINVAL;
}
}
}
......@@ -1228,6 +1249,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
pri_dai->dma_capture.dma_size = 4;
pri_dai->base = regs_base;
pri_dai->quirks = quirks;
pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs;
if (quirks & QUIRK_PRI_6CHAN)
pri_dai->i2s_dai_drv.playback.channels_max = 6;
......@@ -1302,20 +1324,93 @@ static int samsung_i2s_remove(struct platform_device *pdev)
return 0;
}
static const struct samsung_i2s_variant_regs i2sv3_regs = {
.bfs_off = 1,
.rfs_off = 3,
.sdf_off = 5,
.txr_off = 8,
.rclksrc_off = 10,
.mss_off = 11,
.cdclkcon_off = 12,
.lrp_off = 7,
.bfs_mask = 0x3,
.rfs_mask = 0x3,
.ftx0cnt_off = 8,
};
static const struct samsung_i2s_variant_regs i2sv6_regs = {
.bfs_off = 0,
.rfs_off = 4,
.sdf_off = 6,
.txr_off = 8,
.rclksrc_off = 10,
.mss_off = 11,
.cdclkcon_off = 12,
.lrp_off = 15,
.bfs_mask = 0xf,
.rfs_mask = 0x3,
.ftx0cnt_off = 8,
};
static const struct samsung_i2s_variant_regs i2sv7_regs = {
.bfs_off = 0,
.rfs_off = 4,
.sdf_off = 7,
.txr_off = 9,
.rclksrc_off = 11,
.mss_off = 12,
.cdclkcon_off = 22,
.lrp_off = 15,
.bfs_mask = 0xf,
.rfs_mask = 0x7,
.ftx0cnt_off = 0,
};
static const struct samsung_i2s_variant_regs i2sv5_i2s1_regs = {
.bfs_off = 0,
.rfs_off = 3,
.sdf_off = 6,
.txr_off = 8,
.rclksrc_off = 10,
.mss_off = 11,
.cdclkcon_off = 12,
.lrp_off = 15,
.bfs_mask = 0x7,
.rfs_mask = 0x7,
.ftx0cnt_off = 8,
};
static const struct samsung_i2s_dai_data i2sv3_dai_type = {
.dai_type = TYPE_PRI,
.quirks = QUIRK_NO_MUXPSR,
.i2s_variant_regs = &i2sv3_regs,
};
static const struct samsung_i2s_dai_data i2sv5_dai_type = {
.dai_type = TYPE_PRI,
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR,
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
QUIRK_SUPPORTS_IDMA,
.i2s_variant_regs = &i2sv3_regs,
};
static const struct samsung_i2s_dai_data i2sv6_dai_type = {
.dai_type = TYPE_PRI,
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
QUIRK_SUPPORTS_TDM | QUIRK_SUPPORTS_IDMA,
.i2s_variant_regs = &i2sv6_regs,
};
static const struct samsung_i2s_dai_data i2sv7_dai_type = {
.dai_type = TYPE_PRI,
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
QUIRK_SUPPORTS_TDM,
.i2s_variant_regs = &i2sv7_regs,
};
static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 = {
.dai_type = TYPE_PRI,
.quirks = QUIRK_PRI_6CHAN | QUIRK_NEED_RSTCLR,
.i2s_variant_regs = &i2sv5_i2s1_regs,
};
static const struct samsung_i2s_dai_data samsung_dai_type_pri = {
......@@ -1329,10 +1424,13 @@ static const struct samsung_i2s_dai_data samsung_dai_type_sec = {
static struct platform_device_id samsung_i2s_driver_ids[] = {
{
.name = "samsung-i2s",
.driver_data = (kernel_ulong_t)&samsung_dai_type_pri,
.driver_data = (kernel_ulong_t)&i2sv3_dai_type,
}, {
.name = "samsung-i2s-sec",
.driver_data = (kernel_ulong_t)&samsung_dai_type_sec,
}, {
.name = "samsung-i2sv4",
.driver_data = (kernel_ulong_t)&i2sv5_dai_type,
},
{},
};
......@@ -1349,6 +1447,12 @@ static const struct of_device_id exynos_i2s_match[] = {
}, {
.compatible = "samsung,exynos5420-i2s",
.data = &i2sv6_dai_type,
}, {
.compatible = "samsung,exynos7-i2s",
.data = &i2sv7_dai_type,
}, {
.compatible = "samsung,exynos7-i2s1",
.data = &i2sv5_dai_type_i2s1,
},
{},
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment