From fc9cab05837639ce3372870b09d26334fb15b157 Mon Sep 17 00:00:00 2001 From: "oder_chiou@realtek.com" Date: Tue, 7 Nov 2017 12:31:14 +0800 Subject: ASoC: rt5514: The DSP clock can be calibrated by the other clock source Add the option for the DSP clock that can be calibrated by the other clock source. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- include/sound/rt5514.h | 2 + sound/soc/codecs/rt5514-spi.c | 1 + sound/soc/codecs/rt5514.c | 85 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt5514.h | 5 ++- 4 files changed, 92 insertions(+), 1 deletion(-) diff --git a/include/sound/rt5514.h b/include/sound/rt5514.h index ef18494769ee..64d027dbaaca 100644 --- a/include/sound/rt5514.h +++ b/include/sound/rt5514.h @@ -14,6 +14,8 @@ struct rt5514_platform_data { unsigned int dmic_init_delay; + const char *dsp_calib_clk_name; + unsigned int dsp_calib_clk_rate; }; #endif diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 12f2ecf3a4fe..b90d6d5d7ff8 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -370,6 +370,7 @@ int rt5514_spi_burst_read(unsigned int addr, u8 *rxbuf, size_t len) return true; } +EXPORT_SYMBOL_GPL(rt5514_spi_burst_read); /** * rt5514_spi_burst_write - Write data to SPI by rt5514 address. diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 2a5b5d74e697..61ccbc62125b 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -295,6 +295,33 @@ static int rt5514_dsp_voice_wake_up_get(struct snd_kcontrol *kcontrol, return 0; } +static int rt5514_calibration(struct rt5514_priv *rt5514, bool on) +{ + if (on) { + regmap_write(rt5514->regmap, RT5514_ANA_CTRL_PLL3, 0x0000000a); + regmap_update_bits(rt5514->regmap, RT5514_PLL_SOURCE_CTRL, 0xf, + 0xa); + regmap_update_bits(rt5514->regmap, RT5514_PWR_ANA1, 0x301, + 0x301); + regmap_write(rt5514->regmap, RT5514_PLL3_CALIB_CTRL4, + 0x80000000 | rt5514->pll3_cal_value); + regmap_write(rt5514->regmap, RT5514_PLL3_CALIB_CTRL1, + 0x8bb80800); + regmap_update_bits(rt5514->regmap, RT5514_PLL3_CALIB_CTRL5, + 0xc0000000, 0x80000000); + regmap_update_bits(rt5514->regmap, RT5514_PLL3_CALIB_CTRL5, + 0xc0000000, 0xc0000000); + } else { + regmap_update_bits(rt5514->regmap, RT5514_PLL3_CALIB_CTRL5, + 0xc0000000, 0x40000000); + regmap_update_bits(rt5514->regmap, RT5514_PWR_ANA1, 0x301, 0); + regmap_update_bits(rt5514->regmap, RT5514_PLL_SOURCE_CTRL, 0xf, + 0x4); + } + + return 0; +} + static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -302,6 +329,7 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol, struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component); struct snd_soc_codec *codec = rt5514->codec; const struct firmware *fw = NULL; + u8 buf[8]; if (ucontrol->value.integer.value[0] == rt5514->dsp_enabled) return 0; @@ -310,6 +338,35 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol, rt5514->dsp_enabled = ucontrol->value.integer.value[0]; if (rt5514->dsp_enabled) { + if (rt5514->pdata.dsp_calib_clk_name && + !IS_ERR(rt5514->dsp_calib_clk)) { + if (clk_set_rate(rt5514->dsp_calib_clk, + rt5514->pdata.dsp_calib_clk_rate)) + dev_err(codec->dev, + "Can't set rate for mclk"); + + if (clk_prepare_enable(rt5514->dsp_calib_clk)) + dev_err(codec->dev, + "Can't enable dsp_calib_clk"); + + rt5514_calibration(rt5514, true); + + msleep(20); +#if IS_ENABLED(CONFIG_SND_SOC_RT5514_SPI) + rt5514_spi_burst_read(RT5514_PLL3_CALIB_CTRL6 | + RT5514_DSP_MAPPING, + (u8 *)&buf, sizeof(buf)); +#else + dev_err(codec->dev, "There is no SPI driver for" + " loading the firmware\n"); +#endif + rt5514->pll3_cal_value = buf[0] | buf[1] << 8 | + buf[2] << 16 | buf[3] << 24; + + rt5514_calibration(rt5514, false); + clk_disable_unprepare(rt5514->dsp_calib_clk); + } + rt5514_enable_dsp_prepare(rt5514); request_firmware(&fw, RT5514_FIRMWARE1, codec->dev); @@ -341,6 +398,20 @@ static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol, /* DSP run */ regmap_write(rt5514->i2c_regmap, 0x18002f00, 0x00055148); + + if (rt5514->pdata.dsp_calib_clk_name && + !IS_ERR(rt5514->dsp_calib_clk)) { + msleep(20); + + regmap_write(rt5514->i2c_regmap, 0x1800211c, + rt5514->pll3_cal_value); + regmap_write(rt5514->i2c_regmap, 0x18002124, + 0x00220012); + regmap_write(rt5514->i2c_regmap, 0x18002124, + 0x80220042); + regmap_write(rt5514->i2c_regmap, 0x18002124, + 0xe0220042); + } } else { regmap_multi_reg_write(rt5514->i2c_regmap, rt5514_i2c_patch, ARRAY_SIZE(rt5514_i2c_patch)); @@ -1024,12 +1095,22 @@ static int rt5514_set_bias_level(struct snd_soc_codec *codec, static int rt5514_probe(struct snd_soc_codec *codec) { struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); + struct platform_device *pdev = container_of(codec->dev, + struct platform_device, dev); rt5514->mclk = devm_clk_get(codec->dev, "mclk"); if (PTR_ERR(rt5514->mclk) == -EPROBE_DEFER) return -EPROBE_DEFER; + if (rt5514->pdata.dsp_calib_clk_name) { + rt5514->dsp_calib_clk = devm_clk_get(&pdev->dev, + rt5514->pdata.dsp_calib_clk_name); + if (PTR_ERR(rt5514->dsp_calib_clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + } + rt5514->codec = codec; + rt5514->pll3_cal_value = 0x0078b000; return 0; } @@ -1147,6 +1228,10 @@ static int rt5514_parse_dp(struct rt5514_priv *rt5514, struct device *dev) { device_property_read_u32(dev, "realtek,dmic-init-delay-ms", &rt5514->pdata.dmic_init_delay); + device_property_read_string(dev, "realtek,dsp-calib-clk-name", + &rt5514->pdata.dsp_calib_clk_name); + device_property_read_u32(dev, "realtek,dsp-calib-clk-rate", + &rt5514->pdata.dsp_calib_clk_rate); return 0; } diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h index 2dc40e6d8b3f..f0f3400ce6b1 100644 --- a/sound/soc/codecs/rt5514.h +++ b/sound/soc/codecs/rt5514.h @@ -34,7 +34,9 @@ #define RT5514_CLK_CTRL1 0x2104 #define RT5514_CLK_CTRL2 0x2108 #define RT5514_PLL3_CALIB_CTRL1 0x2110 +#define RT5514_PLL3_CALIB_CTRL4 0x2120 #define RT5514_PLL3_CALIB_CTRL5 0x2124 +#define RT5514_PLL3_CALIB_CTRL6 0x2128 #define RT5514_DELAY_BUF_CTRL1 0x2140 #define RT5514_DELAY_BUF_CTRL3 0x2148 #define RT5514_ASRC_IN_CTRL1 0x2180 @@ -272,7 +274,7 @@ struct rt5514_priv { struct rt5514_platform_data pdata; struct snd_soc_codec *codec; struct regmap *i2c_regmap, *regmap; - struct clk *mclk; + struct clk *mclk, *dsp_calib_clk; int sysclk; int sysclk_src; int lrck; @@ -281,6 +283,7 @@ struct rt5514_priv { int pll_in; int pll_out; int dsp_enabled; + unsigned int pll3_cal_value; }; #endif /* __RT5514_H__ */ -- cgit v1.2.3 From e4d0db60e8d25cc62b9b7e32c18e7f6acc136055 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Tue, 7 Nov 2017 15:23:17 +0800 Subject: ASoC: nau8540: reset state machine for channel phase sync The four channel ADCs in NAU85L40 have difference control registers, it is hard to synchronous these four channels without correct sequence. The phase difference will not be a constant and not to conjecture easily. It may be 2.55 degree, or more ,or less. Intended to prevent phase difference of channels, the solution as follows: (1)Channel_Sync need to be enabled. (2)Do soft reset without affecting register when recording done. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8540.c | 23 ++++++++++++++++++++--- sound/soc/codecs/nau8540.h | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c index f9c9933acffb..c10cbffa6314 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c @@ -233,6 +233,19 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new digital_ch1_mux = SOC_DAPM_ENUM("Digital CH1 Select", digital_ch1_enum); +static int aiftx_power_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec); + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + regmap_write(nau8540->regmap, NAU8540_REG_RST, 0x0001); + regmap_write(nau8540->regmap, NAU8540_REG_RST, 0x0000); + } + return 0; +} + static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("MICBIAS2", NAU8540_REG_MIC_BIAS, 11, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS1", NAU8540_REG_MIC_BIAS, 10, 0, NULL, 0), @@ -270,7 +283,8 @@ static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = { SND_SOC_DAPM_MUX("Digital CH1 Mux", SND_SOC_NOPM, 0, 0, &digital_ch1_mux), - SND_SOC_DAPM_AIF_OUT("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT_E("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0, + aiftx_power_control, SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_route nau8540_dapm_routes[] = { @@ -710,9 +724,12 @@ static void nau8540_init_regs(struct nau8540 *nau8540) regmap_update_bits(regmap, NAU8540_REG_CLOCK_CTRL, NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN, NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN); - /* ADC OSR selection, CLK_ADC = Fs * OSR */ + /* ADC OSR selection, CLK_ADC = Fs * OSR; + * Channel time alignment enable. + */ regmap_update_bits(regmap, NAU8540_REG_ADC_SAMPLE_RATE, - NAU8540_ADC_OSR_MASK, NAU8540_ADC_OSR_64); + NAU8540_CH_SYNC | NAU8540_ADC_OSR_MASK, + NAU8540_CH_SYNC | NAU8540_ADC_OSR_64); } static int __maybe_unused nau8540_suspend(struct snd_soc_codec *codec) diff --git a/sound/soc/codecs/nau8540.h b/sound/soc/codecs/nau8540.h index 5db5b224944d..14339f9bb01a 100644 --- a/sound/soc/codecs/nau8540.h +++ b/sound/soc/codecs/nau8540.h @@ -165,6 +165,7 @@ #define NAU8540_TDM_TX_MASK 0xf /* ADC_SAMPLE_RATE (0x3A) */ +#define NAU8540_CH_SYNC (0x1 << 14) #define NAU8540_ADC_OSR_MASK 0x3 #define NAU8540_ADC_OSR_256 0x3 #define NAU8540_ADC_OSR_128 0x2 -- cgit v1.2.3 From 14323ff8c21825e20810e893312f9321f9e4e72c Mon Sep 17 00:00:00 2001 From: John Hsu Date: Tue, 7 Nov 2017 15:23:18 +0800 Subject: ASoC: nau8540: PGA short to ground Change channel PGA input mode selection for better recording quality. The patch shorts the inputs to ground with 12kOhm differentially terminated. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8540.c | 7 +++++++ sound/soc/codecs/nau8540.h | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c index c10cbffa6314..8246486a588d 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c @@ -730,6 +730,13 @@ static void nau8540_init_regs(struct nau8540 *nau8540) regmap_update_bits(regmap, NAU8540_REG_ADC_SAMPLE_RATE, NAU8540_CH_SYNC | NAU8540_ADC_OSR_MASK, NAU8540_CH_SYNC | NAU8540_ADC_OSR_64); + /* PGA input mode selection */ + regmap_update_bits(regmap, NAU8540_REG_FEPGA1, + NAU8540_FEPGA1_MODCH2_SHT | NAU8540_FEPGA1_MODCH1_SHT, + NAU8540_FEPGA1_MODCH2_SHT | NAU8540_FEPGA1_MODCH1_SHT); + regmap_update_bits(regmap, NAU8540_REG_FEPGA2, + NAU8540_FEPGA2_MODCH4_SHT | NAU8540_FEPGA2_MODCH3_SHT, + NAU8540_FEPGA2_MODCH4_SHT | NAU8540_FEPGA2_MODCH3_SHT); } static int __maybe_unused nau8540_suspend(struct snd_soc_codec *codec) diff --git a/sound/soc/codecs/nau8540.h b/sound/soc/codecs/nau8540.h index 14339f9bb01a..7083d4821ce4 100644 --- a/sound/soc/codecs/nau8540.h +++ b/sound/soc/codecs/nau8540.h @@ -184,6 +184,18 @@ #define NAU8540_PRECHARGE_DIS (0x1 << 13) #define NAU8540_GLOBAL_BIAS_EN (0x1 << 12) +/* FEPGA1 (0x69) */ +#define NAU8540_FEPGA1_MODCH2_SHT_SFT 7 +#define NAU8540_FEPGA1_MODCH2_SHT (0x1 << NAU8540_FEPGA1_MODCH2_SHT_SFT) +#define NAU8540_FEPGA1_MODCH1_SHT_SFT 3 +#define NAU8540_FEPGA1_MODCH1_SHT (0x1 << NAU8540_FEPGA1_MODCH1_SHT_SFT) + +/* FEPGA2 (0x6A) */ +#define NAU8540_FEPGA2_MODCH4_SHT_SFT 7 +#define NAU8540_FEPGA2_MODCH4_SHT (0x1 << NAU8540_FEPGA2_MODCH4_SHT_SFT) +#define NAU8540_FEPGA2_MODCH3_SHT_SFT 3 +#define NAU8540_FEPGA2_MODCH3_SHT (0x1 << NAU8540_FEPGA2_MODCH3_SHT_SFT) + /* System Clock Source */ enum { -- cgit v1.2.3 From 6573c0510be611fb886d005b7b2321658dc5df87 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Tue, 7 Nov 2017 15:23:19 +0800 Subject: ASoC: nau8540: fix the record pop noise When the record starts, the driver turns on MICBIAS and the voltage is pulled up for an instant. If the receiver starts to capture the signal between the instant, there is an pop noise in the stream beginning. To avoid the pop noise, the driver makes a delay in the sequence. After MICBIAS powered up, the driver waits 300 ms for the voltage going down. Then turns on the ADC output, and sends signal to receiver. The pop noise can be erased. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8540.c | 47 ++++++++++++++++++++++++++++++++++++++-------- sound/soc/codecs/nau8540.h | 2 ++ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c index 8246486a588d..9565f9a181a9 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c @@ -233,6 +233,28 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new digital_ch1_mux = SOC_DAPM_ENUM("Digital CH1 Select", digital_ch1_enum); +static int adc_power_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + msleep(300); + /* DO12 and DO34 pad output enable */ + regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1, + NAU8540_I2S_DO12_TRI, 0); + regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2, + NAU8540_I2S_DO34_TRI, 0); + } else if (SND_SOC_DAPM_EVENT_OFF(event)) { + regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1, + NAU8540_I2S_DO12_TRI, NAU8540_I2S_DO12_TRI); + regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2, + NAU8540_I2S_DO34_TRI, NAU8540_I2S_DO34_TRI); + } + return 0; +} + static int aiftx_power_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { @@ -260,14 +282,18 @@ static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = { SND_SOC_DAPM_PGA("Frontend PGA3", NAU8540_REG_PWR, 14, 0, NULL, 0), SND_SOC_DAPM_PGA("Frontend PGA4", NAU8540_REG_PWR, 15, 0, NULL, 0), - SND_SOC_DAPM_ADC("ADC1", NULL, - NAU8540_REG_POWER_MANAGEMENT, 0, 0), - SND_SOC_DAPM_ADC("ADC2", NULL, - NAU8540_REG_POWER_MANAGEMENT, 1, 0), - SND_SOC_DAPM_ADC("ADC3", NULL, - NAU8540_REG_POWER_MANAGEMENT, 2, 0), - SND_SOC_DAPM_ADC("ADC4", NULL, - NAU8540_REG_POWER_MANAGEMENT, 3, 0), + SND_SOC_DAPM_ADC_E("ADC1", NULL, + NAU8540_REG_POWER_MANAGEMENT, 0, 0, adc_power_control, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("ADC2", NULL, + NAU8540_REG_POWER_MANAGEMENT, 1, 0, adc_power_control, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("ADC3", NULL, + NAU8540_REG_POWER_MANAGEMENT, 2, 0, adc_power_control, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("ADC4", NULL, + NAU8540_REG_POWER_MANAGEMENT, 3, 0, adc_power_control, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_PGA("ADC CH1", NAU8540_REG_ANALOG_PWR, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("ADC CH2", NAU8540_REG_ANALOG_PWR, 1, 0, NULL, 0), @@ -737,6 +763,11 @@ static void nau8540_init_regs(struct nau8540 *nau8540) regmap_update_bits(regmap, NAU8540_REG_FEPGA2, NAU8540_FEPGA2_MODCH4_SHT | NAU8540_FEPGA2_MODCH3_SHT, NAU8540_FEPGA2_MODCH4_SHT | NAU8540_FEPGA2_MODCH3_SHT); + /* DO12 and DO34 pad output disable */ + regmap_update_bits(regmap, NAU8540_REG_PCM_CTRL1, + NAU8540_I2S_DO12_TRI, NAU8540_I2S_DO12_TRI); + regmap_update_bits(regmap, NAU8540_REG_PCM_CTRL2, + NAU8540_I2S_DO34_TRI, NAU8540_I2S_DO34_TRI); } static int __maybe_unused nau8540_suspend(struct snd_soc_codec *codec) diff --git a/sound/soc/codecs/nau8540.h b/sound/soc/codecs/nau8540.h index 7083d4821ce4..dceb04b23c19 100644 --- a/sound/soc/codecs/nau8540.h +++ b/sound/soc/codecs/nau8540.h @@ -146,6 +146,7 @@ #define NAU8540_I2S_DF_PCM_AB 0x3 /* PCM_CTRL1 (0x11) */ +#define NAU8540_I2S_DO12_TRI (0x1 << 15) #define NAU8540_I2S_LRC_DIV_SFT 12 #define NAU8540_I2S_LRC_DIV_MASK (0x3 << NAU8540_I2S_LRC_DIV_SFT) #define NAU8540_I2S_DO12_OE (0x1 << 4) @@ -156,6 +157,7 @@ #define NAU8540_I2S_BLK_DIV_MASK 0x7 /* PCM_CTRL1 (0x12) */ +#define NAU8540_I2S_DO34_TRI (0x1 << 15) #define NAU8540_I2S_DO34_OE (0x1 << 11) #define NAU8540_I2S_TSLOT_L_MASK 0x3ff -- cgit v1.2.3 From cf6b68d192138d67b49002b499eb507af0c8c56d Mon Sep 17 00:00:00 2001 From: John Hsu Date: Tue, 7 Nov 2017 17:06:32 +0800 Subject: ASoC: nau8824: move key irq after jd done It is possible to get the fake key press interruption when the codec do jack detection. We think it's proper to move the key interruption configuration after jack detection done. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8824.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index 0240759f951c..b7b63ac037a7 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -843,6 +843,11 @@ static void nau8824_jdet_work(struct work_struct *work) event_mask |= SND_JACK_HEADSET; snd_soc_jack_report(nau8824->jack, event, event_mask); + /* Enable short key press and release interruption. */ + regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING, + NAU8824_IRQ_KEY_RELEASE_DIS | + NAU8824_IRQ_KEY_SHORT_PRESS_DIS, 0); + nau8824_sema_release(nau8824); } @@ -850,13 +855,12 @@ static void nau8824_setup_auto_irq(struct nau8824 *nau8824) { struct regmap *regmap = nau8824->regmap; - /* Enable jack ejection, short key press and release interruption. */ + /* Enable jack ejection interruption. */ regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING_1, NAU8824_IRQ_INSERT_EN | NAU8824_IRQ_EJECT_EN, NAU8824_IRQ_EJECT_EN); regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING, - NAU8824_IRQ_EJECT_DIS | NAU8824_IRQ_KEY_RELEASE_DIS | - NAU8824_IRQ_KEY_SHORT_PRESS_DIS, 0); + NAU8824_IRQ_EJECT_DIS, 0); /* Enable internal VCO needed for interruptions */ nau8824_config_sysclk(nau8824, NAU8824_CLK_INTERNAL, 0); regmap_update_bits(regmap, NAU8824_REG_ENA_CTRL, -- cgit v1.2.3 From a2eb62edbd01064cee0c4c00854a25f04237605b Mon Sep 17 00:00:00 2001 From: John Hsu Date: Tue, 7 Nov 2017 17:06:33 +0800 Subject: ASoC: nau8824: condition for clock disable There are headphone and speaker outputs in NAU88L24. During the playback, the codec should not change the clock status when switching these outputs. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8824.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index b7b63ac037a7..8a9a9939827e 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -811,7 +811,8 @@ static void nau8824_eject_jack(struct nau8824 *nau8824) NAU8824_JD_SLEEP_MODE, NAU8824_JD_SLEEP_MODE); /* Close clock for jack type detection at manual mode */ - nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0); + if (dapm->bias_level < SND_SOC_BIAS_PREPARE) + nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0); } static void nau8824_jdet_work(struct work_struct *work) @@ -862,7 +863,8 @@ static void nau8824_setup_auto_irq(struct nau8824 *nau8824) regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING, NAU8824_IRQ_EJECT_DIS, 0); /* Enable internal VCO needed for interruptions */ - nau8824_config_sysclk(nau8824, NAU8824_CLK_INTERNAL, 0); + if (nau8824->dapm->bias_level < SND_SOC_BIAS_PREPARE) + nau8824_config_sysclk(nau8824, NAU8824_CLK_INTERNAL, 0); regmap_update_bits(regmap, NAU8824_REG_ENA_CTRL, NAU8824_JD_SLEEP_MODE, 0); } -- cgit v1.2.3 From cc20c4df1627dd515ea90dd20e2684a8a1c76693 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 6 Nov 2017 14:30:36 +0100 Subject: ASoC: intel: initialize return value properly When CONFIG_SND_SOC_HDAC_HDMI is disabled, we can run into an uninitialized variable: sound/soc/intel/skylake/skl.c: In function 'skl_resume': sound/soc/intel/skylake/skl.c:326:6: error: 'ret' may be used uninitialized in this function [-Werror=maybe-uninitialized] I have run into this on today's linux-next kernel, but it appears that this is an older problem that was just hard to trigger with randconfig builds as CONFIG_SND_SOC_HDAC_HDMI would in effect be impossible to disable when having SND_SOC_INTEL_SKYLAKE enabled. Signed-off-by: Arnd Bergmann Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 31d8634e8aa1..acb0ab470ca6 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -355,6 +355,7 @@ static int skl_resume(struct device *dev) if (ebus->cmd_dma_state) snd_hdac_bus_init_cmd_io(&ebus->bus); + ret = 0; } else { ret = _skl_resume(ebus); -- cgit v1.2.3 From a76d7f5454c688b52dc849e832cc4c6dd0975723 Mon Sep 17 00:00:00 2001 From: Akshu Agrawal Date: Fri, 3 Nov 2017 16:35:44 -0400 Subject: ASoC: AMD: Make the driver name consistent across files This fixes the issue of driver not getting auto loaded with MODULE_ALIAS. find /sys/devices -name modalias -print0 | xargs -0 grep 'audio' /sys/devices/pci0000:00/0000:00:01.0/acp_audio_dma.0.auto/modalias:platform:acp_audio_dma BUG=b:62103837 TEST=boot and check for device in lsmod Signed-off-by: Akshu Agrawal Reviewed-on: https://chromium-review.googlesource.com/678278 Tested-by: Jason Clinton Reviewed-by: Jason Clinton Signed-off-by: Alex Deucher Signed-off-by: Mark Brown --- sound/soc/amd/Makefile | 4 ++-- sound/soc/amd/acp-pcm-dma.c | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile index eed64ff6c73e..f07fd2e2870a 100644 --- a/sound/soc/amd/Makefile +++ b/sound/soc/amd/Makefile @@ -1,5 +1,5 @@ -snd-soc-acp-pcm-objs := acp-pcm-dma.o +acp_audio_dma-objs := acp-pcm-dma.o snd-soc-acp-rt5645-mach-objs := acp-rt5645.o -obj-$(CONFIG_SND_SOC_AMD_ACP) += snd-soc-acp-pcm.o +obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index 73b58ee00383..95c61ecdd1dd 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -40,6 +40,8 @@ #define ST_MAX_BUFFER (ST_PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS) #define ST_MIN_BUFFER ST_MAX_BUFFER +#define DRV_NAME "acp_audio_dma" + static const struct snd_pcm_hardware acp_pcm_hardware_playback = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | @@ -1170,7 +1172,7 @@ static struct platform_driver acp_dma_driver = { .probe = acp_audio_probe, .remove = acp_audio_remove, .driver = { - .name = "acp_audio_dma", + .name = DRV_NAME, .pm = &acp_pm_ops, }, }; @@ -1181,4 +1183,4 @@ MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com"); MODULE_DESCRIPTION("AMD ACP PCM Driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:acp-dma-audio"); +MODULE_ALIAS("platform:"DRV_NAME); -- cgit v1.2.3 From fe83b1b7d7d0ff11210f84f25b8e1ba1afbac76f Mon Sep 17 00:00:00 2001 From: John Hsu Date: Mon, 13 Nov 2017 10:16:17 +0800 Subject: ASoC: nau8540: improve FLL performance Add these parameters to improve the FLL performance. The comments show as follows: (1)ICTRL_LATCH: FLL DSP speed capability control When FLL running at high frequency with long decimal number, DSP needs to operate at high speed. FLL DSP can optimize between performance and power consumption by ICTRL_LATCH.(111 has highest power consumption.) The default setting can be used to reduce power. (2)CUTOFF500: loop filter cutoff frequency at 500Khz It will give the best FLL performance but highest power consumption to enable the cutoff frequency. FLL Loop Filter enable to reduce FLL output noise, especially,(DCO frequency)/(FLL input reference frequency) is not a integer. (3)GAIN_ERR: FLL gain error correction threshold setting The threshold is comparison between DCO and target frequency. The value 1111 has the most sensitive threshold, that is, 1111 can have the most accurate DCO to target frequency. However, the gain error setting conditionally and inversely depends on FLL input reference clock rate. Higher FLL reference input frequency can only set lower gain error, such as 0000 for input reference from MCLK=12.288Mhz. On the other side, if FLL reference input is from Frame Sync, 48KHz, higher error gain can apply such as 1111. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8540.c | 21 ++++++++++++++------- sound/soc/codecs/nau8540.h | 5 +++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c index 9565f9a181a9..b08fb7e243c3 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c @@ -615,7 +615,8 @@ static void nau8540_fll_apply(struct regmap *regmap, NAU8540_CLK_SRC_MASK | NAU8540_CLK_MCLK_SRC_MASK, NAU8540_CLK_SRC_MCLK | fll_param->mclk_src); regmap_update_bits(regmap, NAU8540_REG_FLL1, - NAU8540_FLL_RATIO_MASK, fll_param->ratio); + NAU8540_FLL_RATIO_MASK | NAU8540_ICTRL_LATCH_MASK, + fll_param->ratio | (0x6 << NAU8540_ICTRL_LATCH_SFT)); /* FLL 16-bit fractional input */ regmap_write(regmap, NAU8540_REG_FLL2, fll_param->fll_frac); /* FLL 10-bit integer input */ @@ -636,13 +637,14 @@ static void nau8540_fll_apply(struct regmap *regmap, NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN | NAU8540_FLL_FTR_SW_FILTER); regmap_update_bits(regmap, NAU8540_REG_FLL6, - NAU8540_SDM_EN, NAU8540_SDM_EN); + NAU8540_SDM_EN | NAU8540_CUTOFF500, + NAU8540_SDM_EN | NAU8540_CUTOFF500); } else { regmap_update_bits(regmap, NAU8540_REG_FLL5, NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN | NAU8540_FLL_FTR_SW_MASK, NAU8540_FLL_FTR_SW_ACCU); - regmap_update_bits(regmap, - NAU8540_REG_FLL6, NAU8540_SDM_EN, 0); + regmap_update_bits(regmap, NAU8540_REG_FLL6, + NAU8540_SDM_EN | NAU8540_CUTOFF500, 0); } } @@ -657,17 +659,22 @@ static int nau8540_set_pll(struct snd_soc_codec *codec, int pll_id, int source, switch (pll_id) { case NAU8540_CLK_FLL_MCLK: regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3, - NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_MCLK); + NAU8540_FLL_CLK_SRC_MASK | NAU8540_GAIN_ERR_MASK, + NAU8540_FLL_CLK_SRC_MCLK | 0); break; case NAU8540_CLK_FLL_BLK: regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3, - NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_BLK); + NAU8540_FLL_CLK_SRC_MASK | NAU8540_GAIN_ERR_MASK, + NAU8540_FLL_CLK_SRC_BLK | + (0xf << NAU8540_GAIN_ERR_SFT)); break; case NAU8540_CLK_FLL_FS: regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3, - NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_FS); + NAU8540_FLL_CLK_SRC_MASK | NAU8540_GAIN_ERR_MASK, + NAU8540_FLL_CLK_SRC_FS | + (0xf << NAU8540_GAIN_ERR_SFT)); break; default: diff --git a/sound/soc/codecs/nau8540.h b/sound/soc/codecs/nau8540.h index dceb04b23c19..732b490edf81 100644 --- a/sound/soc/codecs/nau8540.h +++ b/sound/soc/codecs/nau8540.h @@ -100,9 +100,13 @@ #define NAU8540_CLK_MCLK_SRC_MASK 0xf /* FLL1 (0x04) */ +#define NAU8540_ICTRL_LATCH_SFT 10 +#define NAU8540_ICTRL_LATCH_MASK (0x7 << NAU8540_ICTRL_LATCH_SFT) #define NAU8540_FLL_RATIO_MASK 0x7f /* FLL3 (0x06) */ +#define NAU8540_GAIN_ERR_SFT 12 +#define NAU8540_GAIN_ERR_MASK (0xf << NAU8540_GAIN_ERR_SFT) #define NAU8540_FLL_CLK_SRC_SFT 10 #define NAU8540_FLL_CLK_SRC_MASK (0x3 << NAU8540_FLL_CLK_SRC_SFT) #define NAU8540_FLL_CLK_SRC_MCLK (0 << NAU8540_FLL_CLK_SRC_SFT) @@ -127,6 +131,7 @@ /* FLL6 (0x9) */ #define NAU8540_DCO_EN (0x1 << 15) #define NAU8540_SDM_EN (0x1 << 14) +#define NAU8540_CUTOFF500 (0x1 << 13) /* PCM_CTRL0 (0x10) */ #define NAU8540_I2S_BP_SFT 7 -- cgit v1.2.3 From 080f773d226a9c2b0fa0d8f02107518c560f8b77 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Mon, 13 Nov 2017 10:36:28 +0800 Subject: ASoC: nau8824: change FVCO maximum threshold Change the maximum of FDCO which remains between 90MHz-100MHz. FDCO must be within the 90MHz-100MHz or the FFL cannot be guaranteed across the full range of operation. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8824.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index 8a9a9939827e..088e0cef4cb8 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -43,7 +43,7 @@ static bool nau8824_is_jack_inserted(struct nau8824 *nau8824); /* the parameter threshold of FLL */ #define NAU_FREF_MAX 13500000 -#define NAU_FVCO_MAX 124000000 +#define NAU_FVCO_MAX 100000000 #define NAU_FVCO_MIN 90000000 /* scaling for mclk from sysclk_src output */ -- cgit v1.2.3 From e866d87a7de38672f52c6e7567e88c3f82f937dc Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 23 Nov 2017 22:28:00 +0100 Subject: ASoC: wm2000: Delete an error message for a failed memory allocation in wm2000_i2c_probe() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm2000.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 23cde3a0dc11..ce936deed7e3 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -902,7 +902,6 @@ static int wm2000_i2c_probe(struct i2c_client *i2c, wm2000->anc_download_size, GFP_KERNEL); if (wm2000->anc_download == NULL) { - dev_err(&i2c->dev, "Out of memory\n"); ret = -ENOMEM; goto err_supplies; } -- cgit v1.2.3 From cdbd9b0c7211485e08d5128eccf9d0a24d38facd Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 24 Nov 2017 08:02:57 +0100 Subject: ASoC: wm2000: Fix a typo in a comment line Delete a duplicate character in a word of this description. Signed-off-by: Markus Elfring Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm2000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index ce936deed7e3..480ceb07c3ed 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -13,7 +13,7 @@ * 'wm2000_anc.bin' by default (overridable via platform data) at * runtime and is expected to be in flat binary format. This is * generated by Wolfson configuration tools and includes - * system-specific callibration information. If supplied as a + * system-specific calibration information. If supplied as a * sequence of ASCII-encoded hexidecimal bytes this can be converted * into a flat binary with a command such as this on the command line: * -- cgit v1.2.3 From bf0842ba3afa85d37b35e65dedec9a994988e346 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 24 Nov 2017 08:18:14 +0100 Subject: ASoC: wm2000: Improve a size determination in wm2000_i2c_probe() Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm2000.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 480ceb07c3ed..abfa052c07d8 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -826,8 +826,7 @@ static int wm2000_i2c_probe(struct i2c_client *i2c, int reg; u16 id; - wm2000 = devm_kzalloc(&i2c->dev, sizeof(struct wm2000_priv), - GFP_KERNEL); + wm2000 = devm_kzalloc(&i2c->dev, sizeof(*wm2000), GFP_KERNEL); if (!wm2000) return -ENOMEM; -- cgit v1.2.3 From cce7c0ac44832225ca86afff308cf6a5fb19cf2c Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 24 Nov 2017 10:05:43 +0100 Subject: ASoC: wm8903: Delete an error message for a failed memory allocation in wm8903_i2c_probe() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 237eeb9a8b97..51eb7d61d446 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -2020,10 +2020,8 @@ static int wm8903_i2c_probe(struct i2c_client *i2c, wm8903->pdata = devm_kzalloc(&i2c->dev, sizeof(struct wm8903_platform_data), GFP_KERNEL); - if (wm8903->pdata == NULL) { - dev_err(&i2c->dev, "Failed to allocate pdata\n"); + if (!wm8903->pdata) return -ENOMEM; - } if (i2c->irq) { ret = wm8903_set_pdata_irq_trigger(i2c, wm8903->pdata); -- cgit v1.2.3 From 017b9b35cb107c0aeaad2ad770460c49e3f71395 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 24 Nov 2017 10:40:43 +0100 Subject: ASoC: wm8903: Improve two size determinations in wm8903_i2c_probe() Replace the specification of two data structures by pointer dereferences as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 51eb7d61d446..cba90f21161f 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1995,8 +1995,7 @@ static int wm8903_i2c_probe(struct i2c_client *i2c, unsigned int val, irq_pol; int ret, i; - wm8903 = devm_kzalloc(&i2c->dev, sizeof(struct wm8903_priv), - GFP_KERNEL); + wm8903 = devm_kzalloc(&i2c->dev, sizeof(*wm8903), GFP_KERNEL); if (wm8903 == NULL) return -ENOMEM; @@ -2017,9 +2016,8 @@ static int wm8903_i2c_probe(struct i2c_client *i2c, if (pdata) { wm8903->pdata = pdata; } else { - wm8903->pdata = devm_kzalloc(&i2c->dev, - sizeof(struct wm8903_platform_data), - GFP_KERNEL); + wm8903->pdata = devm_kzalloc(&i2c->dev, sizeof(*wm8903->pdata), + GFP_KERNEL); if (!wm8903->pdata) return -ENOMEM; -- cgit v1.2.3 From 2dbb29cd977fc281f71f8895abce7e382efe77e1 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 23 Nov 2017 21:30:07 +0100 Subject: ASoC: twl4030: Delete an error message for a failed memory allocation in twl4030_get_pdata() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index cfe72b9d4356..90691701b082 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -240,7 +240,6 @@ static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_codec *codec) sizeof(struct twl4030_codec_data), GFP_KERNEL); if (!pdata) { - dev_err(codec->dev, "Can not allocate memory\n"); of_node_put(twl4030_codec_node); return NULL; } -- cgit v1.2.3 From 14a07f1d8c4c64af29566316df0415052e8bdfe4 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 23 Nov 2017 20:42:20 +0100 Subject: ASoC: da7218: Delete two error messages for a failed memory allocation in da7218_of_to_pdata() Omit extra messages for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7218.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index 56564ce90cb6..25ab7443d803 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -2455,10 +2455,8 @@ static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_codec *codec) u32 of_val32; pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_warn(codec->dev, "Failed to allocate memory for pdata\n"); + if (!pdata) return NULL; - } if (of_property_read_u32(np, "dlg,micbias1-lvl-millivolt", &of_val32) >= 0) pdata->micbias1_lvl = da7218_of_micbias_lvl(codec, of_val32); @@ -2527,8 +2525,6 @@ static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_codec *codec) hpldet_pdata = devm_kzalloc(codec->dev, sizeof(*hpldet_pdata), GFP_KERNEL); if (!hpldet_pdata) { - dev_warn(codec->dev, - "Failed to allocate memory for hpldet pdata\n"); of_node_put(hpldet_np); return pdata; } -- cgit v1.2.3 From 392b79e20b41cfdc174d31bd4b004bbd874de4d9 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 23 Nov 2017 20:50:44 +0100 Subject: ASoC: da7218: Improve a size determination in da7218_i2c_probe() Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7218.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index 25ab7443d803..96c644a15b11 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -3269,8 +3269,7 @@ static int da7218_i2c_probe(struct i2c_client *i2c, struct da7218_priv *da7218; int ret; - da7218 = devm_kzalloc(&i2c->dev, sizeof(struct da7218_priv), - GFP_KERNEL); + da7218 = devm_kzalloc(&i2c->dev, sizeof(*da7218), GFP_KERNEL); if (!da7218) return -ENOMEM; -- cgit v1.2.3 From 13d5ea5f10b7359cd0f846179fe0b2411e12cfeb Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 23 Nov 2017 17:56:54 +0100 Subject: ASoC: da7213: Delete an error message for a failed memory allocation in da7213_fw_to_pdata() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7213.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 41d9b1da27c2..d1b77a0e3b74 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1654,10 +1654,8 @@ static struct da7213_platform_data u32 fw_val32; pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_warn(codec->dev, "Failed to allocate memory for pdata\n"); + if (!pdata) return NULL; - } if (device_property_read_u32(dev, "dlg,micbias1-lvl", &fw_val32) >= 0) pdata->micbias1_lvl = da7213_of_micbias_lvl(codec, fw_val32); -- cgit v1.2.3 From 8080699a3649cb0a0aed2c650a7a3a76c2025b30 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 23 Nov 2017 18:15:30 +0100 Subject: ASoC: da7213: Improve a size determination in da7213_i2c_probe() Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7213.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index d1b77a0e3b74..b2b4e90fc02a 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1853,8 +1853,7 @@ static int da7213_i2c_probe(struct i2c_client *i2c, struct da7213_priv *da7213; int ret; - da7213 = devm_kzalloc(&i2c->dev, sizeof(struct da7213_priv), - GFP_KERNEL); + da7213 = devm_kzalloc(&i2c->dev, sizeof(*da7213), GFP_KERNEL); if (!da7213) return -ENOMEM; -- cgit v1.2.3 From 277631ccff503f2a8e8150574c9773a8383fc926 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 23 Nov 2017 09:26:08 +0100 Subject: ASoC: cs42l56: Delete an error message for a failed memory allocation in cs42l56_i2c_probe() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l56.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index cb6ca85f1536..13ee46217d78 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1210,11 +1210,9 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client, pdata = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l56_platform_data), GFP_KERNEL); - if (!pdata) { - dev_err(&i2c_client->dev, - "could not allocate pdata\n"); + if (!pdata) return -ENOMEM; - } + if (i2c_client->dev.of_node) { ret = cs42l56_handle_of_data(i2c_client, &cs42l56->pdata); -- cgit v1.2.3 From e8d8b98c0a6edab5d6cc0292e1ed603d8d4ff5b6 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 23 Nov 2017 09:33:15 +0100 Subject: ASoC: cs42l56: Improve two size determinations in cs42l56_i2c_probe() Replace the specification of two data structures by pointer dereferences as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l56.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 13ee46217d78..fd7b8d32c2b2 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1190,9 +1190,7 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client, unsigned int alpha_rev, metal_rev; unsigned int reg; - cs42l56 = devm_kzalloc(&i2c_client->dev, - sizeof(struct cs42l56_private), - GFP_KERNEL); + cs42l56 = devm_kzalloc(&i2c_client->dev, sizeof(*cs42l56), GFP_KERNEL); if (cs42l56 == NULL) return -ENOMEM; cs42l56->dev = &i2c_client->dev; @@ -1207,8 +1205,7 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client, if (pdata) { cs42l56->pdata = *pdata; } else { - pdata = devm_kzalloc(&i2c_client->dev, - sizeof(struct cs42l56_platform_data), + pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; -- cgit v1.2.3 From e04db58c1252305e8a4d4178a3cfdbef802cff74 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 22 Nov 2017 22:08:06 +0100 Subject: ASoC: cs42l52: Delete an error message for a failed memory allocation in cs42l52_i2c_probe() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l52.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 0d9c4a57301b..e8645f2ac0d9 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1118,10 +1118,9 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, pdata = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l52_platform_data), GFP_KERNEL); - if (!pdata) { - dev_err(&i2c_client->dev, "could not allocate pdata\n"); + if (!pdata) return -ENOMEM; - } + if (i2c_client->dev.of_node) { if (of_property_read_bool(i2c_client->dev.of_node, "cirrus,mica-differential-cfg")) -- cgit v1.2.3 From cd9e0b8282653d8bdc2c8b799eeb26ee034cdd06 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 22 Nov 2017 22:11:30 +0100 Subject: ASoC: cs42l52: Improve two size determinations in cs42l52_i2c_probe() Replace the specification of two data structures by pointer dereferences as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l52.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index e8645f2ac0d9..9731e5dff291 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1100,8 +1100,7 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, unsigned int reg; u32 val32; - cs42l52 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l52_private), - GFP_KERNEL); + cs42l52 = devm_kzalloc(&i2c_client->dev, sizeof(*cs42l52), GFP_KERNEL); if (cs42l52 == NULL) return -ENOMEM; cs42l52->dev = &i2c_client->dev; @@ -1115,9 +1114,8 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, if (pdata) { cs42l52->pdata = *pdata; } else { - pdata = devm_kzalloc(&i2c_client->dev, - sizeof(struct cs42l52_platform_data), - GFP_KERNEL); + pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata), + GFP_KERNEL); if (!pdata) return -ENOMEM; -- cgit v1.2.3 From af0f6c5820845b66c76296f281da5cf916d7e094 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Wed, 22 Nov 2017 12:56:41 -0800 Subject: ASoC: ts3a227e: Map BTN_0 to KEY_PLAYPAUSE The Android 3.5mm Headset jack specification mentions that BTN_0 should be mapped to KEY_MEDIA, but this is less logical than KEY_PLAYPAUSE, which has much broader userspace support. For example, the Chrome OS userspace now supports KEY_PLAYPAUSE to toggle play/pause of videos and audio, but does not handle KEY_MEDIA. Furthermore, Android itself now supports KEY_PLAYPAUSE equivalently, as the new USB headset spec requires KEY_PLAYPAUSE for BTN_0. https://source.android.com/devices/accessories/headset/usb-headset-spec Signed-off-by: Benson Leung Signed-off-by: Mark Brown --- sound/soc/codecs/ts3a227e.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index 738e04b09116..1271e7e1fc78 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -241,7 +241,7 @@ int ts3a227e_enable_jack_detect(struct snd_soc_component *component, { struct ts3a227e *ts3a227e = snd_soc_component_get_drvdata(component); - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA); + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); -- cgit v1.2.3 From af1b1cefd735c919d3185ce06b549c2b121067ba Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Wed, 22 Nov 2017 12:56:42 -0800 Subject: ASoC: rk3399_gru_sound: Map BTN_0 to KEY_PLAYPAUSE The Android 3.5mm Headset jack specification mentions that BTN_0 should be mapped to KEY_MEDIA, but this is less logical than KEY_PLAYPAUSE, which has much broader userspace support. For example, the Chrome OS userspace now supports KEY_PLAYPAUSE to toggle play/pause of videos and audio, but does not handle KEY_MEDIA. Furthermore, Android itself now supports KEY_PLAYPAUSE equivalently, as the new USB headset spec requires KEY_PLAYPAUSE for BTN_0. https://source.android.com/devices/accessories/headset/usb-headset-spec Signed-off-by: Benson Leung Signed-off-by: Mark Brown --- sound/soc/rockchip/rk3399_gru_sound.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index d64fbbd50544..fa6cd1de828b 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -206,7 +206,8 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd) return ret; } - snd_jack_set_key(rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_MEDIA); + snd_jack_set_key( + rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); snd_jack_set_key( rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); snd_jack_set_key( -- cgit v1.2.3 From 5f6d1df8ced6bb52453149f96d9b7005058641b6 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Wed, 22 Nov 2017 12:56:43 -0800 Subject: ASoC: qcom: apq8016-sbc: Map BTN_0 to KEY_PLAYPAUSE The Android 3.5mm Headset jack specification mentions that BTN_0 should be mapped to KEY_MEDIA, but this is less logical than KEY_PLAYPAUSE, which has much broader userspace support. For example, the Chrome OS userspace now supports KEY_PLAYPAUSE to toggle play/pause of videos and audio, but does not handle KEY_MEDIA. Furthermore, Android itself now supports KEY_PLAYPAUSE equivalently, as the new USB headset spec requires KEY_PLAYPAUSE for BTN_0. https://source.android.com/devices/accessories/headset/usb-headset-spec Signed-off-by: Benson Leung Signed-off-by: Mark Brown --- sound/soc/qcom/apq8016_sbc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index d49adc822a11..03851fedd1e2 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -92,7 +92,7 @@ static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) jack = pdata->jack.jack; - snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_MEDIA); + snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP); snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); -- cgit v1.2.3 From 8ee649283b1e542aedba007f6c828d6767c48e0d Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Wed, 22 Nov 2017 12:56:39 -0800 Subject: ASoC: Intel: kbl_rt5663_rt5514_max98927: Map BTN_0 to KEY_PLAYPAUSE The Android 3.5mm Headset jack specification mentions that BTN_0 should be mapped to KEY_MEDIA, but this is less logical than KEY_PLAYPAUSE, which has much broader userspace support. For example, the Chrome OS userspace now supports KEY_PLAYPAUSE to toggle play/pause of videos and audio, but does not handle KEY_MEDIA. Furthermore, Android itself now supports KEY_PLAYPAUSE equivalently, as the new USB headset spec requires KEY_PLAYPAUSE for BTN_0. https://source.android.com/devices/accessories/headset/usb-headset-spec Signed-off-by: Benson Leung Signed-off-by: Mark Brown --- sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index e7672831bc49..38512f0d1a73 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -195,7 +195,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) } jack = &ctx->kabylake_headset; - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA); + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); -- cgit v1.2.3 From 38a5882e4292d135cebabad0b56c9420dfdd80a5 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Wed, 22 Nov 2017 12:56:40 -0800 Subject: ASoC: Intel: kbl_rt5663_max98927: Map BTN_0 to KEY_PLAYPAUSE The Android 3.5mm Headset jack specification mentions that BTN_0 should be mapped to KEY_MEDIA, but this is less logical than KEY_PLAYPAUSE, which has much broader userspace support. For example, the Chrome OS userspace now supports KEY_PLAYPAUSE to toggle play/pause of videos and audio, but does not handle KEY_MEDIA. Furthermore, Android itself now supports KEY_PLAYPAUSE equivalently, as the new USB headset spec requires KEY_PLAYPAUSE for BTN_0. https://source.android.com/devices/accessories/headset/usb-headset-spec Signed-off-by: Benson Leung Signed-off-by: Mark Brown --- sound/soc/intel/boards/kbl_rt5663_max98927.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index 6f9a8bcf20f3..94a34db4f8c0 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -225,7 +225,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) } jack = &ctx->kabylake_headset; - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA); + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); -- cgit v1.2.3 From 4be0ffdf284046eb7289fa66cc7b2eb8d7efdc64 Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Wed, 22 Nov 2017 16:02:25 +0100 Subject: ASoC: stm32: fix sync property description in SAI bindings SAI sync property must be described in SAI subnodes section, as it is a property of child node. This patch fixes commit 14f0e5f8d97e632695d92f41f2e91d10d8005d47 "ASoC: stm32: Add synchronization to SAI bindings". Signed-off-by: Olivier Moysan Acked-by: Rob Herring Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/st,stm32-sai.txt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt index 1f9cd7095337..b1acc1a256ba 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt @@ -20,11 +20,6 @@ Required properties: Optional properties: - resets: Reference to a reset controller asserting the SAI - - st,sync: specify synchronization mode. - By default SAI sub-block is in asynchronous mode. - This property sets SAI sub-block as slave of another SAI sub-block. - Must contain the phandle and index of the sai sub-block providing - the synchronization. SAI subnodes: Two subnodes corresponding to SAI sub-block instances A et B can be defined. @@ -44,6 +39,13 @@ SAI subnodes required properties: - pinctrl-names: should contain only value "default" - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt +SAI subnodes Optional properties: + - st,sync: specify synchronization mode. + By default SAI sub-block is in asynchronous mode. + This property sets SAI sub-block as slave of another SAI sub-block. + Must contain the phandle and index of the sai sub-block providing + the synchronization. + The device node should contain one 'port' child node with one child 'endpoint' node, according to the bindings defined in Documentation/devicetree/bindings/ graph.txt. -- cgit v1.2.3 From 7dd0d835582ff72b0b3bd0f4fa074967dff1ce82 Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Wed, 22 Nov 2017 16:02:26 +0100 Subject: ASoC: stm32: sai: simplify sync modes management Use function of_find_device_by_node() to retrieve SAI synchro provider device and private data. This allows to remove registration of probed SAI in a linked list. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai.c | 105 ++++++++++------------------------------------ 1 file changed, 22 insertions(+), 83 deletions(-) diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index d6f71a3406e9..0a1f06418bf4 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -28,16 +28,6 @@ #include "stm32_sai.h" -static LIST_HEAD(sync_providers); -static DEFINE_MUTEX(sync_mutex); - -struct sync_provider { - struct list_head link; - struct device_node *node; - int (*sync_conf)(void *data, int synco); - void *data; -}; - static const struct stm32_sai_conf stm32_sai_conf_f4 = { .version = SAI_STM32F4, }; @@ -70,9 +60,8 @@ static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci) return 0; } -static int stm32_sai_sync_conf_provider(void *data, int synco) +static int stm32_sai_sync_conf_provider(struct stm32_sai_data *sai, int synco) { - struct stm32_sai_data *sai = (struct stm32_sai_data *)data; u32 prev_synco; int ret; @@ -103,73 +92,34 @@ static int stm32_sai_sync_conf_provider(void *data, int synco) return 0; } -static int stm32_sai_set_sync_provider(struct device_node *np, int synco) +static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, + struct device_node *np_provider, + int synco, int synci) { - struct sync_provider *provider; + struct platform_device *pdev = of_find_device_by_node(np_provider); + struct stm32_sai_data *sai_provider; int ret; - mutex_lock(&sync_mutex); - list_for_each_entry(provider, &sync_providers, link) { - if (provider->node == np) { - ret = provider->sync_conf(provider->data, synco); - mutex_unlock(&sync_mutex); - return ret; - } + if (!pdev) { + dev_err(&sai_client->pdev->dev, + "Device not found for node %s\n", np_provider->name); + return -ENODEV; } - mutex_unlock(&sync_mutex); - /* SAI sync provider not found */ - return -ENODEV; -} - -static int stm32_sai_set_sync(struct stm32_sai_data *sai, - struct device_node *np_provider, - int synco, int synci) -{ - int ret; + sai_provider = platform_get_drvdata(pdev); + if (!sai_provider) { + dev_err(&sai_client->pdev->dev, + "SAI sync provider data not found\n"); + return -EINVAL; + } /* Configure sync client */ - stm32_sai_sync_conf_client(sai, synci); + ret = stm32_sai_sync_conf_client(sai_client, synci); + if (ret < 0) + return ret; /* Configure sync provider */ - ret = stm32_sai_set_sync_provider(np_provider, synco); - - return ret; -} - -static int stm32_sai_sync_add_provider(struct platform_device *pdev, - void *data) -{ - struct sync_provider *sp; - - sp = devm_kzalloc(&pdev->dev, sizeof(*sp), GFP_KERNEL); - if (!sp) - return -ENOMEM; - - sp->node = of_node_get(pdev->dev.of_node); - sp->data = data; - sp->sync_conf = &stm32_sai_sync_conf_provider; - - mutex_lock(&sync_mutex); - list_add(&sp->link, &sync_providers); - mutex_unlock(&sync_mutex); - - return 0; -} - -static void stm32_sai_sync_del_provider(struct device_node *np) -{ - struct sync_provider *sp; - - mutex_lock(&sync_mutex); - list_for_each_entry(sp, &sync_providers, link) { - if (sp->node == np) { - list_del(&sp->link); - of_node_put(sp->node); - break; - } - } - mutex_unlock(&sync_mutex); + return stm32_sai_sync_conf_provider(sai_provider, synco); } static int stm32_sai_probe(struct platform_device *pdev) @@ -179,7 +129,6 @@ static int stm32_sai_probe(struct platform_device *pdev) struct reset_control *rst; struct resource *res; const struct of_device_id *of_id; - int ret; sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); if (!sai) @@ -231,27 +180,17 @@ static int stm32_sai_probe(struct platform_device *pdev) reset_control_deassert(rst); } - ret = stm32_sai_sync_add_provider(pdev, sai); - if (ret < 0) - return ret; - sai->set_sync = &stm32_sai_set_sync; - sai->pdev = pdev; + sai->set_sync = &stm32_sai_set_sync; platform_set_drvdata(pdev, sai); - ret = of_platform_populate(np, NULL, NULL, &pdev->dev); - if (ret < 0) - stm32_sai_sync_del_provider(np); - - return ret; + return of_platform_populate(np, NULL, NULL, &pdev->dev); } static int stm32_sai_remove(struct platform_device *pdev) { of_platform_depopulate(&pdev->dev); - stm32_sai_sync_del_provider(pdev->dev.of_node); - return 0; } -- cgit v1.2.3 From 512d1bb4e86bd0fd4d665d4e454a3486236a419f Mon Sep 17 00:00:00 2001 From: olivier moysan Date: Wed, 22 Nov 2017 16:02:27 +0100 Subject: ASoC: stm32: sai: use devm_of_platform_populate() Use devm_of_platform_populate() instead of of_platform_depopulate() to simplify driver code. Signed-off-by: Benjamin Gaignard Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 0a1f06418bf4..d743b7dd52fb 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -124,7 +124,6 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, static int stm32_sai_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct stm32_sai_data *sai; struct reset_control *rst; struct resource *res; @@ -184,14 +183,7 @@ static int stm32_sai_probe(struct platform_device *pdev) sai->set_sync = &stm32_sai_set_sync; platform_set_drvdata(pdev, sai); - return of_platform_populate(np, NULL, NULL, &pdev->dev); -} - -static int stm32_sai_remove(struct platform_device *pdev) -{ - of_platform_depopulate(&pdev->dev); - - return 0; + return devm_of_platform_populate(&pdev->dev); } MODULE_DEVICE_TABLE(of, stm32_sai_ids); @@ -202,7 +194,6 @@ static struct platform_driver stm32_sai_driver = { .of_match_table = stm32_sai_ids, }, .probe = stm32_sai_probe, - .remove = stm32_sai_remove, }; module_platform_driver(stm32_sai_driver); -- cgit v1.2.3 From ddedd797943df21a2464420744d117e930a43af8 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 22 Nov 2017 15:50:46 +0100 Subject: ASoC: cs42l73: Delete an error message for a failed memory allocation in cs42l73_i2c_probe() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l73.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 3df2c473ab88..978cfbbad408 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1307,10 +1307,9 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, pdata = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l73_platform_data), GFP_KERNEL); - if (!pdata) { - dev_err(&i2c_client->dev, "could not allocate pdata\n"); + if (!pdata) return -ENOMEM; - } + if (i2c_client->dev.of_node) { if (of_property_read_u32(i2c_client->dev.of_node, "chgfreq", &val32) >= 0) -- cgit v1.2.3 From 68fa08c665e51b2fe100876692e57bca3aea7711 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 22 Nov 2017 16:07:42 +0100 Subject: ASoC: cs42l73: Improve two size determinations in cs42l73_i2c_probe() Replace the specification of two data structures by pointer dereferences as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l73.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 978cfbbad408..dde37e569ade 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1289,8 +1289,7 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, unsigned int reg; u32 val32; - cs42l73 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l73_private), - GFP_KERNEL); + cs42l73 = devm_kzalloc(&i2c_client->dev, sizeof(*cs42l73), GFP_KERNEL); if (!cs42l73) return -ENOMEM; @@ -1304,9 +1303,8 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, if (pdata) { cs42l73->pdata = *pdata; } else { - pdata = devm_kzalloc(&i2c_client->dev, - sizeof(struct cs42l73_platform_data), - GFP_KERNEL); + pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata), + GFP_KERNEL); if (!pdata) return -ENOMEM; -- cgit v1.2.3 From 316c85c3db55588893f51907de3424f85020f0eb Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 22 Nov 2017 17:17:48 +0100 Subject: ASoC: wm0010: Delete an error message for a failed memory allocation in wm0010_boot() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm0010.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index 4f5f5710b569..0147d2fb7b0a 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -655,11 +655,8 @@ static int wm0010_boot(struct snd_soc_codec *codec) ret = -ENOMEM; len = pll_rec.length + 8; out = kzalloc(len, GFP_KERNEL | GFP_DMA); - if (!out) { - dev_err(codec->dev, - "Failed to allocate RX buffer\n"); + if (!out) goto abort; - } img_swap = kzalloc(len, GFP_KERNEL | GFP_DMA); if (!img_swap) -- cgit v1.2.3 From 410afed04b130fc1c22f82b10b20aed1636d2f15 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 22 Nov 2017 20:35:06 +0100 Subject: ASoC: cs35l32: Delete two error messages for a failed memory allocation in cs35l32_i2c_probe() Omit extra messages for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 7e9806206648..e41d8ebe6eea 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -358,10 +358,8 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client, cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l32_private), GFP_KERNEL); - if (!cs35l32) { - dev_err(&i2c_client->dev, "could not allocate codec\n"); + if (!cs35l32) return -ENOMEM; - } i2c_set_clientdata(i2c_client, cs35l32); @@ -378,10 +376,9 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client, pdata = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l32_platform_data), GFP_KERNEL); - if (!pdata) { - dev_err(&i2c_client->dev, "could not allocate pdata\n"); + if (!pdata) return -ENOMEM; - } + if (i2c_client->dev.of_node) { ret = cs35l32_handle_of_data(i2c_client, &cs35l32->pdata); -- cgit v1.2.3 From b28ad41ec831b099dccac1f84a9cfb40b0650724 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 22 Nov 2017 20:40:47 +0100 Subject: ASoC: cs35l32: Improve two size determinations in cs35l32_i2c_probe() Replace the specification of two data structures by pointer dereferences as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index e41d8ebe6eea..bc3a72e4c4ed 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -355,9 +355,7 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client, unsigned int devid = 0; unsigned int reg; - - cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l32_private), - GFP_KERNEL); + cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(*cs35l32), GFP_KERNEL); if (!cs35l32) return -ENOMEM; @@ -373,9 +371,8 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client, if (pdata) { cs35l32->pdata = *pdata; } else { - pdata = devm_kzalloc(&i2c_client->dev, - sizeof(struct cs35l32_platform_data), - GFP_KERNEL); + pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata), + GFP_KERNEL); if (!pdata) return -ENOMEM; -- cgit v1.2.3 From 4dbd91549200574c71e10176d0ca37beca6703ec Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 22 Nov 2017 21:13:29 +0100 Subject: ASoC: cs35l34: Delete two error messages for a failed memory allocation in cs35l34_i2c_probe() Omit extra messages for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l34.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index 1e05026bedca..6cbdbbe53940 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -1007,10 +1007,8 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client, cs35l34 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l34_private), GFP_KERNEL); - if (!cs35l34) { - dev_err(&i2c_client->dev, "could not allocate codec\n"); + if (!cs35l34) return -ENOMEM; - } i2c_set_clientdata(i2c_client, cs35l34); cs35l34->regmap = devm_regmap_init_i2c(i2c_client, &cs35l34_regmap); @@ -1047,11 +1045,9 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client, pdata = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l34_platform_data), GFP_KERNEL); - if (!pdata) { - dev_err(&i2c_client->dev, - "could not allocate pdata\n"); + if (!pdata) return -ENOMEM; - } + if (i2c_client->dev.of_node) { ret = cs35l34_handle_of_data(i2c_client, pdata); if (ret != 0) -- cgit v1.2.3 From 7f9f3abd285433e224faaf854b165b189270c923 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 22 Nov 2017 21:17:42 +0100 Subject: ASoC: cs35l34: Improve two size determinations in cs35l34_i2c_probe() Replace the specification of two data structures by pointer dereferences as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l34.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index 6cbdbbe53940..0600d5264c4c 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -1004,9 +1004,7 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client, unsigned int devid = 0; unsigned int reg; - cs35l34 = devm_kzalloc(&i2c_client->dev, - sizeof(struct cs35l34_private), - GFP_KERNEL); + cs35l34 = devm_kzalloc(&i2c_client->dev, sizeof(*cs35l34), GFP_KERNEL); if (!cs35l34) return -ENOMEM; @@ -1042,9 +1040,8 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client, if (pdata) { cs35l34->pdata = *pdata; } else { - pdata = devm_kzalloc(&i2c_client->dev, - sizeof(struct cs35l34_platform_data), - GFP_KERNEL); + pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata), + GFP_KERNEL); if (!pdata) return -ENOMEM; -- cgit v1.2.3 From 0cab20cec0b663b7be8e2be5998d5a4113647f86 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Sun, 19 Nov 2017 23:45:49 -0800 Subject: ASoC: pcm512x: add missing MODULE_DESCRIPTION/AUTHOR/LICENSE This change resolves a new compile-time warning when built as a loadable module: WARNING: modpost: missing MODULE_LICENSE() in sound/soc/codecs/snd-soc-pcm512x-spi.o see include/linux/module.h for more information This adds the license as "GPL v2", which matches the header of the file. MODULE_DESCRIPTION and MODULE_AUTHOR are also added. Signed-off-by: Jesse Chan Signed-off-by: Mark Brown --- sound/soc/codecs/pcm512x-spi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c index 25c63510ae15..7cdd2dc4fd79 100644 --- a/sound/soc/codecs/pcm512x-spi.c +++ b/sound/soc/codecs/pcm512x-spi.c @@ -70,3 +70,7 @@ static struct spi_driver pcm512x_spi_driver = { }; module_spi_driver(pcm512x_spi_driver); + +MODULE_DESCRIPTION("ASoC PCM512x codec driver - SPI"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 74231295c67ada29a4566272d8ac4886d09f3e83 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 20 Nov 2017 23:12:01 +0100 Subject: ASoC: fsl_ssi: remove duplicated flag setting in fsl_ssi_setup_reg_vals() We don't need to set CCSR_SSI_SIER_RFF0_EN / CCSR_SSI_SIER_TFE0_EN bits in reg->rx.sier / reg->tx.sier variables in a non-AC'97 mode considering we had just initialized these variables to these very values unconditionally a few lines earlier. Signed-off-by: Maciej S. Szmigiero Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 424bafaf51ef..9e97a0529f37 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -600,9 +600,7 @@ static void fsl_ssi_setup_reg_vals(struct fsl_ssi_private *ssi_private) if (!fsl_ssi_is_ac97(ssi_private)) { reg->rx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE; - reg->rx.sier |= CCSR_SSI_SIER_RFF0_EN; reg->tx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE; - reg->tx.sier |= CCSR_SSI_SIER_TFE0_EN; } if (ssi_private->use_dma) { -- cgit v1.2.3 From eaa53216c5909ae1567d15888e55d9b1d7269ca7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 9 Nov 2017 00:19:33 +0000 Subject: ASoC: don't use codec hw_write on uda1380 uda1380 driver is using codec hw_write/control_data, but it is redundant code. This patch cleanup these Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/uda1380.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 926c81ae8185..44448023edb0 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -37,7 +37,7 @@ struct uda1380_priv { struct snd_soc_codec *codec; unsigned int dac_clk; struct work_struct work; - void *control_data; + struct i2c_client *i2c; }; /* @@ -92,6 +92,7 @@ static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec, static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { + struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec); u8 data[3]; /* data is @@ -111,10 +112,10 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg, if (!snd_soc_codec_is_active(codec) && (reg >= UDA1380_MVOL)) return 0; pr_debug("uda1380: hw write %x val %x\n", reg, value); - if (codec->hw_write(codec->control_data, data, 3) == 3) { + if (i2c_master_send(uda1380->i2c, data, 3) == 3) { unsigned int val; - i2c_master_send(codec->control_data, data, 1); - i2c_master_recv(codec->control_data, data, 2); + i2c_master_send(uda1380->i2c, data, 1); + i2c_master_recv(uda1380->i2c, data, 2); val = (data[0]<<8) | data[1]; if (val != value) { pr_debug("uda1380: READ BACK VAL %x\n", @@ -130,6 +131,7 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg, static void uda1380_sync_cache(struct snd_soc_codec *codec) { + struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec); int reg; u8 data[3]; u16 *cache = codec->reg_cache; @@ -139,7 +141,7 @@ static void uda1380_sync_cache(struct snd_soc_codec *codec) data[0] = reg; data[1] = (cache[reg] & 0xff00) >> 8; data[2] = cache[reg] & 0x00ff; - if (codec->hw_write(codec->control_data, data, 3) != 3) + if (i2c_master_send(uda1380->i2c, data, 3) != 3) dev_err(codec->dev, "%s: write to reg 0x%x failed\n", __func__, reg); } @@ -148,6 +150,7 @@ static void uda1380_sync_cache(struct snd_soc_codec *codec) static int uda1380_reset(struct snd_soc_codec *codec) { struct uda1380_platform_data *pdata = codec->dev->platform_data; + struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec); if (gpio_is_valid(pdata->gpio_reset)) { gpio_set_value(pdata->gpio_reset, 1); @@ -160,7 +163,7 @@ static int uda1380_reset(struct snd_soc_codec *codec) data[1] = 0; data[2] = 0; - if (codec->hw_write(codec->control_data, data, 3) != 3) { + if (i2c_master_send(uda1380->i2c, data, 3) != 3) { dev_err(codec->dev, "%s: failed\n", __func__); return -EIO; } @@ -695,9 +698,6 @@ static int uda1380_probe(struct snd_soc_codec *codec) uda1380->codec = codec; - codec->hw_write = (hw_write_t)i2c_master_send; - codec->control_data = uda1380->control_data; - if (!gpio_is_valid(pdata->gpio_power)) { ret = uda1380_reset(codec); if (ret) @@ -772,7 +772,7 @@ static int uda1380_i2c_probe(struct i2c_client *i2c, } i2c_set_clientdata(i2c, uda1380); - uda1380->control_data = i2c; + uda1380->i2c = i2c; ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai)); -- cgit v1.2.3 From ce9544dc8f9a83f9e8ff08eca30821edbe51d177 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 9 Nov 2017 00:19:48 +0000 Subject: ASoC: don't use codec hw_write on tlv320dac33 uda1380 driver is using codec hw_write/control_data, but it is redundant code. This patch cleanup these Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 5b94a151539c..80a26418827c 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -121,7 +121,7 @@ struct tlv320dac33_priv { unsigned int uthr; enum dac33_state state; - void *control_data; + struct i2c_client *i2c; }; static const u8 dac33_reg[DAC33_CACHEREGNUM] = { @@ -200,7 +200,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg, /* If powered off, return the cached value */ if (dac33->chip_power) { - val = i2c_smbus_read_byte_data(codec->control_data, value[0]); + val = i2c_smbus_read_byte_data(dac33->i2c, value[0]); if (val < 0) { dev_err(codec->dev, "Read failed (%d)\n", val); value[0] = dac33_read_reg_cache(codec, reg); @@ -233,7 +233,7 @@ static int dac33_write(struct snd_soc_codec *codec, unsigned int reg, dac33_write_reg_cache(codec, data[0], data[1]); if (dac33->chip_power) { - ret = codec->hw_write(codec->control_data, data, 2); + ret = i2c_master_send(dac33->i2c, data, 2); if (ret != 2) dev_err(codec->dev, "Write failed (%d)\n", ret); else @@ -280,7 +280,7 @@ static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg, if (dac33->chip_power) { /* We need to set autoincrement mode for 16 bit writes */ data[0] |= DAC33_I2C_ADDR_AUTOINC; - ret = codec->hw_write(codec->control_data, data, 3); + ret = i2c_master_send(dac33->i2c, data, 3); if (ret != 3) dev_err(codec->dev, "Write failed (%d)\n", ret); else @@ -1379,8 +1379,6 @@ static int dac33_soc_probe(struct snd_soc_codec *codec) struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); int ret = 0; - codec->control_data = dac33->control_data; - codec->hw_write = (hw_write_t) i2c_master_send; dac33->codec = codec; /* Read the tlv320dac33 ID registers */ @@ -1499,7 +1497,7 @@ static int dac33_i2c_probe(struct i2c_client *client, if (dac33 == NULL) return -ENOMEM; - dac33->control_data = client; + dac33->i2c = client; mutex_init(&dac33->mutex); spin_lock_init(&dac33->lock); -- cgit v1.2.3 From fac3f5e20dcecc2aa03272c5d2d36d253883c6ce Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 9 Nov 2017 01:04:09 +0000 Subject: ASoC: don't use codec hw_write on cx20442/omap-ams-delta cx20442/omap-ams-delta driver is using codec hw_write/control_data, but it is redundant code. This patch cleanup these Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/cx20442.c | 23 ++++++++++------------- sound/soc/omap/ams-delta.c | 4 ++-- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 46b1fbb66eba..2083f7eb9de2 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -26,7 +26,7 @@ struct cx20442_priv { - void *control_data; + struct tty_struct *tty; struct regulator *por; }; @@ -163,9 +163,9 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg, if (reg >= codec->driver->reg_cache_size) return -EINVAL; - /* hw_write and control_data pointers required for talking to the modem + /* tty and write pointers required for talking to the modem * are expected to be set by the line discipline initialization code */ - if (!codec->hw_write || !cx20442->control_data) + if (!cx20442->tty || !cx20442->tty->ops->write) return -EIO; old = reg_cache[reg]; @@ -194,7 +194,7 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg, return -ENOMEM; dev_dbg(codec->dev, "%s: %s\n", __func__, buf); - if (codec->hw_write(cx20442->control_data, buf, len) != len) + if (cx20442->tty->ops->write(cx20442->tty, buf, len) != len) return -EIO; return 0; @@ -252,8 +252,7 @@ static void v253_close(struct tty_struct *tty) cx20442 = snd_soc_codec_get_drvdata(codec); /* Prevent the codec driver from further accessing the modem */ - codec->hw_write = NULL; - cx20442->control_data = NULL; + cx20442->tty = NULL; codec->component.card->pop_time = 0; } @@ -276,12 +275,11 @@ static void v253_receive(struct tty_struct *tty, cx20442 = snd_soc_codec_get_drvdata(codec); - if (!cx20442->control_data) { + if (!cx20442->tty) { /* First modem response, complete setup procedure */ /* Set up codec driver access to modem controls */ - cx20442->control_data = tty; - codec->hw_write = (hw_write_t)tty->ops->write; + cx20442->tty = tty; codec->component.card->pop_time = 1; } } @@ -367,10 +365,9 @@ static int cx20442_codec_probe(struct snd_soc_codec *codec) cx20442->por = regulator_get(codec->dev, "POR"); if (IS_ERR(cx20442->por)) dev_warn(codec->dev, "failed to get the regulator"); - cx20442->control_data = NULL; + cx20442->tty = NULL; snd_soc_codec_set_drvdata(codec, cx20442); - codec->hw_write = NULL; codec->component.card->pop_time = 0; return 0; @@ -381,8 +378,8 @@ static int cx20442_codec_remove(struct snd_soc_codec *codec) { struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec); - if (cx20442->control_data) { - struct tty_struct *tty = cx20442->control_data; + if (cx20442->tty) { + struct tty_struct *tty = cx20442->tty; tty_hangup(tty); } diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index d40219678700..cb72c1e57da0 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -105,7 +105,7 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol, int pin, changed = 0; /* Refuse any mode changes if we are not able to control the codec. */ - if (!cx20442_codec->hw_write) + if (!cx20442_codec->component.card->pop_time) return -EUNATCH; if (ucontrol->value.enumerated.item[0] >= control->items) @@ -345,7 +345,7 @@ static void cx81801_receive(struct tty_struct *tty, if (!codec) return; - if (!codec->hw_write) { + if (!codec->component.card->pop_time) { /* First modem response, complete setup procedure */ /* Initialize timer used for config pulse generation */ -- cgit v1.2.3 From 3bd333677d6091d989068b0f7ff7aba975e62dc5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 9 Nov 2017 01:04:37 +0000 Subject: ASoC: don't use codec hw_write on twl6040 twl6040 driver is using codec hw_write/control_data, but it is redundant code. This patch cleanup these Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/twl6040.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 1773ff84ee3b..a8e6941a1868 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -106,10 +106,12 @@ static const struct snd_pcm_hw_constraint_list sysclk_constraints[] = { { .count = ARRAY_SIZE(hp_rates), .list = hp_rates, }, }; +#define to_twl6040(codec) dev_get_drvdata((codec)->dev->parent) + static unsigned int twl6040_read(struct snd_soc_codec *codec, unsigned int reg) { struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); - struct twl6040 *twl6040 = codec->control_data; + struct twl6040 *twl6040 = to_twl6040(codec); u8 value; if (reg >= TWL6040_CACHEREGNUM) @@ -171,7 +173,7 @@ static inline void twl6040_update_dl12_cache(struct snd_soc_codec *codec, static int twl6040_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { - struct twl6040 *twl6040 = codec->control_data; + struct twl6040 *twl6040 = to_twl6040(codec); if (reg >= TWL6040_CACHEREGNUM) return -EIO; @@ -572,7 +574,7 @@ EXPORT_SYMBOL_GPL(twl6040_get_trim_value); int twl6040_get_hs_step_size(struct snd_soc_codec *codec) { - struct twl6040 *twl6040 = codec->control_data; + struct twl6040 *twl6040 = to_twl6040(codec); if (twl6040_get_revid(twl6040) < TWL6040_REV_ES1_3) /* For ES under ES_1.3 HS step is 2 mV */ @@ -830,7 +832,7 @@ static const struct snd_soc_dapm_route intercon[] = { static int twl6040_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - struct twl6040 *twl6040 = codec->control_data; + struct twl6040 *twl6040 = to_twl6040(codec); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); int ret = 0; @@ -922,7 +924,7 @@ static int twl6040_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; - struct twl6040 *twl6040 = codec->control_data; + struct twl6040 *twl6040 = to_twl6040(codec); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); int ret; @@ -964,7 +966,7 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai, static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id id, int mute) { - struct twl6040 *twl6040 = codec->control_data; + struct twl6040 *twl6040 = to_twl6040(codec); struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); int hslctl, hsrctl, earctl; int hflctl, hfrctl; @@ -1108,7 +1110,6 @@ static struct snd_soc_dai_driver twl6040_dai[] = { static int twl6040_probe(struct snd_soc_codec *codec) { struct twl6040_data *priv; - struct twl6040 *twl6040 = dev_get_drvdata(codec->dev->parent); struct platform_device *pdev = to_platform_device(codec->dev); int ret = 0; @@ -1119,7 +1120,6 @@ static int twl6040_probe(struct snd_soc_codec *codec) snd_soc_codec_set_drvdata(codec, priv); priv->codec = codec; - codec->control_data = twl6040; priv->plug_irq = platform_get_irq(pdev, 0); if (priv->plug_irq < 0) { -- cgit v1.2.3 From 866b9c81ad8450eb1e2a0132b4bd9fd909afd647 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 9 Nov 2017 01:04:54 +0000 Subject: ASoC: don't use codec hw_write on max98926 max98926 driver is using codec hw_write/control_data, but it is redundant code. This patch cleanup these Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/max98926.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index 03d07bf4d942..7b1d1b0fa879 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -490,7 +490,7 @@ static int max98926_probe(struct snd_soc_codec *codec) struct max98926_priv *max98926 = snd_soc_codec_get_drvdata(codec); max98926->codec = codec; - codec->control_data = max98926->regmap; + /* Hi-Z all the slots */ regmap_write(max98926->regmap, MAX98926_DOUT_HIZ_CFG4, 0xF0); return 0; -- cgit v1.2.3 From 68fea7cd3f3722cf3d3b7f30e9b5667133446936 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 9 Nov 2017 01:05:11 +0000 Subject: ASoC: don't use codec hw_write on max98927 max98927 driver is using codec hw_write/control_data, but it is redundant code. This patch cleanup these Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/max98927.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index a1d39353719d..f701fdc81175 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -682,7 +682,6 @@ static int max98927_probe(struct snd_soc_codec *codec) struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); max98927->codec = codec; - codec->control_data = max98927->regmap; /* Software Reset */ regmap_write(max98927->regmap, -- cgit v1.2.3 From c001bf633a910cfc8a5b84b80634db4636bf1724 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Nov 2017 01:04:08 +0000 Subject: ASoC: use internal reg_cache on uda1380 Codec reg_cache is legacy feature and very few driver only are using it. But, ALSA SoC framework needs to support it. Codec will be merged into Component in the future, so, let's remove legacy and unused feature from framework. This patch implements ALSA SoC reg_cache feature into driver, and don't use ALSA SoC framework's feature. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/uda1380.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 44448023edb0..46a495b4da8d 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -38,6 +38,7 @@ struct uda1380_priv { unsigned int dac_clk; struct work_struct work; struct i2c_client *i2c; + u16 *reg_cache; }; /* @@ -63,7 +64,9 @@ static unsigned long uda1380_cache_dirty; static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec, unsigned int reg) { - u16 *cache = codec->reg_cache; + struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec); + u16 *cache = uda1380->reg_cache; + if (reg == UDA1380_RESET) return 0; if (reg >= UDA1380_CACHEREGNUM) @@ -77,7 +80,8 @@ static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec, static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec, u16 reg, unsigned int value) { - u16 *cache = codec->reg_cache; + struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec); + u16 *cache = uda1380->reg_cache; if (reg >= UDA1380_CACHEREGNUM) return; @@ -134,7 +138,7 @@ static void uda1380_sync_cache(struct snd_soc_codec *codec) struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec); int reg; u8 data[3]; - u16 *cache = codec->reg_cache; + u16 *cache = uda1380->reg_cache; /* Sync reg_cache with the hardware */ for (reg = 0; reg < UDA1380_MVOL; reg++) { @@ -722,16 +726,9 @@ static int uda1380_probe(struct snd_soc_codec *codec) static const struct snd_soc_codec_driver soc_codec_dev_uda1380 = { .probe = uda1380_probe, - .read = uda1380_read_reg_cache, - .write = uda1380_write, .set_bias_level = uda1380_set_bias_level, .suspend_bias_off = true, - .reg_cache_size = ARRAY_SIZE(uda1380_reg), - .reg_word_size = sizeof(u16), - .reg_cache_default = uda1380_reg, - .reg_cache_step = 1, - .component_driver = { .controls = uda1380_snd_controls, .num_controls = ARRAY_SIZE(uda1380_snd_controls), @@ -771,6 +768,13 @@ static int uda1380_i2c_probe(struct i2c_client *i2c, return ret; } + uda1380->reg_cache = devm_kmemdup(&i2c->dev, + uda1380_reg, + ARRAY_SIZE(uda1380_reg) * sizeof(u16), + GFP_KERNEL); + if (!uda1380->reg_cache) + return -ENOMEM; + i2c_set_clientdata(i2c, uda1380); uda1380->i2c = i2c; -- cgit v1.2.3 From c4305af43a80158fba0d2801be9a0e774634add0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Nov 2017 01:04:25 +0000 Subject: ASoC: use internal reg_cache on tlv320dac33 Codec reg_cache is legacy feature and very few driver only are using it. But, ALSA SoC framework needs to support it. Codec will be merged into Component in the future, so, let's remove legacy and unused feature from framework. This patch implements ALSA SoC reg_cache feature into driver, and don't use ALSA SoC framework's feature. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 80a26418827c..675f5b1b90a6 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -106,6 +106,7 @@ struct tlv320dac33_priv { int mode1_latency; /* latency caused by the i2c writes in * us */ u8 burst_bclkdiv; /* BCLK divider value in burst mode */ + u8 *reg_cache; unsigned int burst_rate; /* Interface speed in Burst modes */ int keep_bclk; /* Keep the BCLK continuously running @@ -173,7 +174,8 @@ static const u8 dac33_reg[DAC33_CACHEREGNUM] = { static inline unsigned int dac33_read_reg_cache(struct snd_soc_codec *codec, unsigned reg) { - u8 *cache = codec->reg_cache; + struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); + u8 *cache = dac33->reg_cache; if (reg >= DAC33_CACHEREGNUM) return 0; @@ -183,7 +185,8 @@ static inline unsigned int dac33_read_reg_cache(struct snd_soc_codec *codec, static inline void dac33_write_reg_cache(struct snd_soc_codec *codec, u8 reg, u8 value) { - u8 *cache = codec->reg_cache; + struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); + u8 *cache = dac33->reg_cache; if (reg >= DAC33_CACHEREGNUM) return; @@ -243,19 +246,6 @@ static int dac33_write(struct snd_soc_codec *codec, unsigned int reg, return ret; } -static int dac33_write_locked(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); - int ret; - - mutex_lock(&dac33->mutex); - ret = dac33_write(codec, reg, value); - mutex_unlock(&dac33->mutex); - - return ret; -} - #define DAC33_I2C_ADDR_AUTOINC 0x80 static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) @@ -1432,13 +1422,9 @@ static int dac33_soc_remove(struct snd_soc_codec *codec) } static const struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = { - .read = dac33_read_reg_cache, - .write = dac33_write_locked, .set_bias_level = dac33_set_bias_level, .idle_bias_off = true, - .reg_cache_size = ARRAY_SIZE(dac33_reg), - .reg_word_size = sizeof(u8), - .reg_cache_default = dac33_reg, + .probe = dac33_soc_probe, .remove = dac33_soc_remove, @@ -1497,6 +1483,13 @@ static int dac33_i2c_probe(struct i2c_client *client, if (dac33 == NULL) return -ENOMEM; + dac33->reg_cache = devm_kmemdup(&client->dev, + dac33_reg, + ARRAY_SIZE(dac33_reg) * sizeof(u8), + GFP_KERNEL); + if (!dac33->reg_cache) + return -ENOMEM; + dac33->i2c = client; mutex_init(&dac33->mutex); spin_lock_init(&dac33->lock); -- cgit v1.2.3 From 39b5a0f80c07f41440f38761e4b8d36bf2072007 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Nov 2017 01:04:42 +0000 Subject: ASoC: cx20442: don't use reg_cache Codec reg_cache is legacy feature and very few driver only are using it. But, ALSA SoC framework needs to support it. Codec will be merged into Component in the future, so, let's remove legacy and unused feature from framework. cx20442 is using reg_cache but it is only 1byte, and it doesn't use snd_soc_write/read/update_bits function which uses reg_cache. reg_cache user is only debugfs. Let's clean reg_cache for now. But let's keep .write function since it can be used for new additional feature. .read will not be used, let's remove. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/cx20442.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 2083f7eb9de2..6b6f8e44369b 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -88,17 +88,6 @@ static const struct snd_soc_dapm_route cx20442_audio_map[] = { {"ADC", NULL, "Input Mixer"}, }; -static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u8 *reg_cache = codec->reg_cache; - - if (reg >= codec->driver->reg_cache_size) - return -EINVAL; - - return reg_cache[reg]; -} - enum v253_vls { V253_VLS_NONE = 0, V253_VLS_T, @@ -123,6 +112,8 @@ enum v253_vls { V253_VLS_TEST, }; +#if 0 +/* FIXME : these function will be re-used */ static int cx20442_pm_to_v253_vls(u8 value) { switch (value & ~(1 << CX20442_AGC)) { @@ -199,7 +190,7 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg, return 0; } - +#endif /* * Line discpline related code @@ -399,11 +390,7 @@ static const struct snd_soc_codec_driver cx20442_codec_dev = { .probe = cx20442_codec_probe, .remove = cx20442_codec_remove, .set_bias_level = cx20442_set_bias_level, - .reg_cache_default = &cx20442_reg, - .reg_cache_size = 1, - .reg_word_size = sizeof(u8), - .read = cx20442_read_reg_cache, - .write = cx20442_write, + .component_driver = { .dapm_widgets = cx20442_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(cx20442_dapm_widgets), -- cgit v1.2.3 From 93a00c467fe998bf5716cbc9cabc127046054782 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Nov 2017 01:04:58 +0000 Subject: ASoC: don't use snd_soc_write/read on twl6040 twl6040 doesn't use regmap nor reg_cache. Its write/read are done through twl6040_reg_write/read. This driver directly calling these functions, but sometimes using snd_soc_write/read. As part of cleanup, snd_soc_codec_driver::write, read will be removed soon. Then, write/read access through snd_soc_write/read will doesn't work on this driver, since it doesn't use regmap nor reg_cache. This patch replace snd_soc_write/read to twl6040_write/read. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/twl6040.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index a8e6941a1868..3b895b4b451c 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -543,7 +543,7 @@ int twl6040_get_dl1_gain(struct snd_soc_codec *codec) if (snd_soc_dapm_get_pin_status(dapm, "HSOR") || snd_soc_dapm_get_pin_status(dapm, "HSOL")) { - u8 val = snd_soc_read(codec, TWL6040_REG_HSLCTL); + u8 val = twl6040_read(codec, TWL6040_REG_HSLCTL); if (val & TWL6040_HSDACMODE) /* HSDACL in LP mode */ return -8; /* -8dB */ @@ -1158,8 +1158,6 @@ static int twl6040_remove(struct snd_soc_codec *codec) static const struct snd_soc_codec_driver soc_codec_dev_twl6040 = { .probe = twl6040_probe, .remove = twl6040_remove, - .read = twl6040_read, - .write = twl6040_write, .set_bias_level = twl6040_set_bias_level, .suspend_bias_off = true, .ignore_pmdown_time = true, -- cgit v1.2.3 From 3bb0f7c31b1aedd0f85c675297031281799145d7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 14 Nov 2017 01:05:17 +0000 Subject: ASoC: don't use snd_soc_write/read on twl4030 twl4030 doesn't use regmap nor reg_cache. Its write/read are done through twl4030_reg_write/read. This driver directly calling these functions, but sometimes using snd_soc_write/read. As part of cleanup, snd_soc_codec_driver::write, read will be removed soon. Then, write/read access through snd_soc_write/read will doesn't work on this driver, since it doesn't use regmap nor reg_cache. This patch replace snd_soc_write/read to twl4030_write/read. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 90691701b082..8798182959c1 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -850,14 +850,14 @@ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol, int mask = (1 << fls(max)) - 1; ucontrol->value.integer.value[0] = - (snd_soc_read(codec, reg) >> shift) & mask; + (twl4030_read(codec, reg) >> shift) & mask; if (ucontrol->value.integer.value[0]) ucontrol->value.integer.value[0] = max + 1 - ucontrol->value.integer.value[0]; if (shift != rshift) { ucontrol->value.integer.value[1] = - (snd_soc_read(codec, reg) >> rshift) & mask; + (twl4030_read(codec, reg) >> rshift) & mask; if (ucontrol->value.integer.value[1]) ucontrol->value.integer.value[1] = max + 1 - ucontrol->value.integer.value[1]; @@ -908,9 +908,9 @@ static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, int mask = (1<value.integer.value[0] = - (snd_soc_read(codec, reg) >> shift) & mask; + (twl4030_read(codec, reg) >> shift) & mask; ucontrol->value.integer.value[1] = - (snd_soc_read(codec, reg2) >> shift) & mask; + (twl4030_read(codec, reg2) >> shift) & mask; if (ucontrol->value.integer.value[0]) ucontrol->value.integer.value[0] = @@ -2195,8 +2195,6 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec) static const struct snd_soc_codec_driver soc_codec_dev_twl4030 = { .probe = twl4030_soc_probe, .remove = twl4030_soc_remove, - .read = twl4030_read, - .write = twl4030_write, .set_bias_level = twl4030_set_bias_level, .idle_bias_off = true, -- cgit v1.2.3 From ef2e8175eb19011f756469d4d14f4207bf7f289c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Nov 2017 06:27:09 +0000 Subject: ASoC: add snd_soc_disconnect_sync() Now, we have snd_card_disconnect_sync() on ALSA framework. snd_soc_disconnect_sync() is ASoC version of it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 2 ++ sound/soc/soc-core.c | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 1a7323238c49..22f479e1da0a 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -494,6 +494,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num); int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num); #endif +void snd_soc_disconnect_sync(struct device *dev); + struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, const char *dai_link, int stream); struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c0edac80df34..9047046c749c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1392,6 +1392,16 @@ static int soc_init_dai_link(struct snd_soc_card *card, return 0; } +void snd_soc_disconnect_sync(struct device *dev) +{ + struct snd_soc_component *component = snd_soc_lookup_component(dev, NULL); + + if (!component || !component->card) + return; + + snd_card_disconnect_sync(component->card->snd_card); +} + /** * snd_soc_add_dai_link - Add a DAI link dynamically * @card: The ASoC card to which the DAI link is added -- cgit v1.2.3 From 180d9ef58104dfae78622d01910b9b7756701134 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 6 Nov 2017 08:41:37 +0000 Subject: ASoC: rsnd: call snd_soc_disconnect_sync() when remove Renesas R-Car sound driver should be stopped if unbinded during playbacking/capturing. Otherwise clock open/close counter mismatch happen. One note is that we can't skip from remove function (= return -Exxx) in such case if user used unbind. Because unbind function doesn't check return value from each driver's remove function. This means we must to stop and remove driver in remove function. Now ASoC has snd_soc_disconnect_sync() for this purpose. Let's use it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f12a88a21dfa..bd64dc6ec1c3 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1496,6 +1496,8 @@ static int rsnd_remove(struct platform_device *pdev) }; int ret = 0, i; + snd_soc_disconnect_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); for_each_rsnd_dai(rdai, priv, i) { -- cgit v1.2.3 From 823dbb6eb08a2865bcd236b4f52b1b9de216418a Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 27 Nov 2017 23:33:29 +0100 Subject: ALSA: pcm: add SNDRV_PCM_FORMAT_{S,U}20 This format is similar to existing SNDRV_PCM_FORMAT_{S,U}20_3 that keep 20-bit PCM samples in 3 bytes, however i.MX6 platform SSI FIFO does not allow 3-byte accesses (including DMA) so a 4-byte (more conventional) format is needed for it. Signed-off-by: Maciej S. Szmigiero Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 8 ++++++++ include/sound/soc-dai.h | 2 ++ include/uapi/sound/asound.h | 9 +++++++++ sound/core/pcm_misc.c | 19 ++++++++++++++++++- 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 24febf9e177c..e054c583d3b3 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -169,6 +169,10 @@ struct snd_pcm_ops { #define SNDRV_PCM_FMTBIT_IMA_ADPCM _SNDRV_PCM_FMTBIT(IMA_ADPCM) #define SNDRV_PCM_FMTBIT_MPEG _SNDRV_PCM_FMTBIT(MPEG) #define SNDRV_PCM_FMTBIT_GSM _SNDRV_PCM_FMTBIT(GSM) +#define SNDRV_PCM_FMTBIT_S20_LE _SNDRV_PCM_FMTBIT(S20_LE) +#define SNDRV_PCM_FMTBIT_U20_LE _SNDRV_PCM_FMTBIT(U20_LE) +#define SNDRV_PCM_FMTBIT_S20_BE _SNDRV_PCM_FMTBIT(S20_BE) +#define SNDRV_PCM_FMTBIT_U20_BE _SNDRV_PCM_FMTBIT(U20_BE) #define SNDRV_PCM_FMTBIT_SPECIAL _SNDRV_PCM_FMTBIT(SPECIAL) #define SNDRV_PCM_FMTBIT_S24_3LE _SNDRV_PCM_FMTBIT(S24_3LE) #define SNDRV_PCM_FMTBIT_U24_3LE _SNDRV_PCM_FMTBIT(U24_3LE) @@ -202,6 +206,8 @@ struct snd_pcm_ops { #define SNDRV_PCM_FMTBIT_FLOAT SNDRV_PCM_FMTBIT_FLOAT_LE #define SNDRV_PCM_FMTBIT_FLOAT64 SNDRV_PCM_FMTBIT_FLOAT64_LE #define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE +#define SNDRV_PCM_FMTBIT_S20 SNDRV_PCM_FMTBIT_S20_LE +#define SNDRV_PCM_FMTBIT_U20 SNDRV_PCM_FMTBIT_U20_LE #endif #ifdef SNDRV_BIG_ENDIAN #define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_BE @@ -213,6 +219,8 @@ struct snd_pcm_ops { #define SNDRV_PCM_FMTBIT_FLOAT SNDRV_PCM_FMTBIT_FLOAT_BE #define SNDRV_PCM_FMTBIT_FLOAT64 SNDRV_PCM_FMTBIT_FLOAT64_BE #define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE +#define SNDRV_PCM_FMTBIT_S20 SNDRV_PCM_FMTBIT_S20_BE +#define SNDRV_PCM_FMTBIT_U20 SNDRV_PCM_FMTBIT_U20_BE #endif struct snd_pcm_file { diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 58acd00cae19..d970879944fc 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -102,6 +102,8 @@ struct snd_compr_stream; SNDRV_PCM_FMTBIT_S16_BE |\ SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S20_3BE |\ + SNDRV_PCM_FMTBIT_S20_LE |\ + SNDRV_PCM_FMTBIT_S20_BE |\ SNDRV_PCM_FMTBIT_S24_3LE |\ SNDRV_PCM_FMTBIT_S24_3BE |\ SNDRV_PCM_FMTBIT_S32_LE |\ diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index c227ccba60ae..07d61583fd02 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -214,6 +214,11 @@ typedef int __bitwise snd_pcm_format_t; #define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22) #define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23) #define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24) +#define SNDRV_PCM_FORMAT_S20_LE ((__force snd_pcm_format_t) 25) /* in four bytes, LSB justified */ +#define SNDRV_PCM_FORMAT_S20_BE ((__force snd_pcm_format_t) 26) /* in four bytes, LSB justified */ +#define SNDRV_PCM_FORMAT_U20_LE ((__force snd_pcm_format_t) 27) /* in four bytes, LSB justified */ +#define SNDRV_PCM_FORMAT_U20_BE ((__force snd_pcm_format_t) 28) /* in four bytes, LSB justified */ +/* gap in the numbering for a future standard linear format */ #define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31) #define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32) /* in three bytes */ #define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33) /* in three bytes */ @@ -248,6 +253,8 @@ typedef int __bitwise snd_pcm_format_t; #define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_LE #define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_LE #define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE +#define SNDRV_PCM_FORMAT_S20 SNDRV_PCM_FORMAT_S20_LE +#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_LE #endif #ifdef SNDRV_BIG_ENDIAN #define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_BE @@ -259,6 +266,8 @@ typedef int __bitwise snd_pcm_format_t; #define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_BE #define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_BE #define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE +#define SNDRV_PCM_FORMAT_S20 SNDRV_PCM_FORMAT_S20_BE +#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_BE #endif typedef int __bitwise snd_pcm_subformat_t; diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 9be81025372f..c4eb561d2008 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -163,13 +163,30 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = { .width = 32, .phys = 32, .le = 0, .signd = 0, .silence = { 0x69, 0x69, 0x69, 0x69 }, }, - /* FIXME: the following three formats are not defined properly yet */ + /* FIXME: the following two formats are not defined properly yet */ [SNDRV_PCM_FORMAT_MPEG] = { .le = -1, .signd = -1, }, [SNDRV_PCM_FORMAT_GSM] = { .le = -1, .signd = -1, }, + [SNDRV_PCM_FORMAT_S20_LE] = { + .width = 20, .phys = 32, .le = 1, .signd = 1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_S20_BE] = { + .width = 20, .phys = 32, .le = 0, .signd = 1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_U20_LE] = { + .width = 20, .phys = 32, .le = 1, .signd = 0, + .silence = { 0x00, 0x00, 0x08, 0x00 }, + }, + [SNDRV_PCM_FORMAT_U20_BE] = { + .width = 20, .phys = 32, .le = 0, .signd = 0, + .silence = { 0x00, 0x08, 0x00, 0x00 }, + }, + /* FIXME: the following format is not defined properly yet */ [SNDRV_PCM_FORMAT_SPECIAL] = { .le = -1, .signd = -1, }, -- cgit v1.2.3 From a4a1b737032daf42e1e2ccd70bfceca56464ccac Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 27 Nov 2017 12:58:51 +0000 Subject: ALSA: drivers: make array 'names' const, reduces object code size Don't populate array 'names' on the stack but instead make them static. Makes the object code smaller by 50 bytes: Before: text data bss dec hex filename 21237 9192 1120 31549 7b3d linux/sound/drivers/dummy.o After: text data bss dec hex filename 21095 9280 1120 31495 7b07 linux/sound/drivers/dummy.o (gcc version 7.2.0 x86_64) Signed-off-by: Colin Ian King Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/drivers/dummy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 7b2b1f766b00..69db45bc0197 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -830,7 +830,7 @@ static int snd_dummy_capsrc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el static int snd_dummy_iobox_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info) { - const char *const names[] = { "None", "CD Player" }; + static const char *const names[] = { "None", "CD Player" }; return snd_ctl_enum_info(info, 1, 2, names); } -- cgit v1.2.3 From 044ace5e3fc95f8df1197b7eaeadee0b35dfcef5 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 11 Nov 2017 18:34:04 +0100 Subject: ALSA: hal2: Improve a size determination in hal2_create() Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/mips/hal2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index 37d378a26a50..c8904e732aaa 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -814,7 +814,7 @@ static int hal2_create(struct snd_card *card, struct snd_hal2 **rchip) struct hpc3_regs *hpc3 = hpc3c0; int err; - hal2 = kzalloc(sizeof(struct snd_hal2), GFP_KERNEL); + hal2 = kzalloc(sizeof(*hal2), GFP_KERNEL); if (!hal2) return -ENOMEM; -- cgit v1.2.3 From cdc4398b399cad38e36be64faf3752aa12a44022 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 11 Nov 2017 20:02:07 +0100 Subject: ALSA: sgio2audio: Improve a size determination in snd_sgio2audio_create() Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/mips/sgio2audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index 71c942162c25..9fb68b35de5a 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -840,7 +840,7 @@ static int snd_sgio2audio_create(struct snd_card *card, if (!(readq(&mace->perif.audio.control) & AUDIO_CONTROL_CODEC_PRESENT)) return -ENOENT; - chip = kzalloc(sizeof(struct snd_sgio2audio), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; -- cgit v1.2.3 From 4d0272ca40dfe524ce8d1ae350f0a246ef849d4b Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 22 Nov 2017 17:43:25 +0100 Subject: ALSA: gus: Delete an error message for a failed memory allocation in snd_gf1_dma_transfer_block() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/isa/gus/gus_dma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/isa/gus/gus_dma.c b/sound/isa/gus/gus_dma.c index 36c27c832360..7f95f452f106 100644 --- a/sound/isa/gus/gus_dma.c +++ b/sound/isa/gus/gus_dma.c @@ -201,10 +201,9 @@ int snd_gf1_dma_transfer_block(struct snd_gus_card * gus, struct snd_gf1_dma_block *block; block = kmalloc(sizeof(*block), atomic ? GFP_ATOMIC : GFP_KERNEL); - if (block == NULL) { - snd_printk(KERN_ERR "gf1: DMA transfer failure; not enough memory\n"); + if (!block) return -ENOMEM; - } + *block = *__block; block->next = NULL; -- cgit v1.2.3 From cf576fe5fd74cdabf7fc3fd8ac3b9abea9b964f8 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 16 Nov 2017 11:22:26 +0100 Subject: ALSA: korg1212: Delete a duplicate function call "release_firmware" in snd_korg1212_create() The function "release_firmware" is called in the current implementation of the function "_request_firmware" after a failure was detected. Link: https://elixir.free-electrons.com/linux/v4.14-rc8/source/drivers/base/firmware_class.c#L1196 Such a call should therefore not be repeated directly after the corresponding error information was received in the local variable "err" of the function "snd_korg1212_create". Thus remove a misplaced function call. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/pci/korg1212/korg1212.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index c7b007164c99..4206ba44d8bb 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -2348,7 +2348,6 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, err = request_firmware(&dsp_code, "korg/k1212.dsp", &pci->dev); if (err < 0) { - release_firmware(dsp_code); snd_printk(KERN_ERR "firmware not available\n"); snd_korg1212_free(korg1212); return err; -- cgit v1.2.3 From 6dbc6caf6602607edf45d486aaf1949888e5053e Mon Sep 17 00:00:00 2001 From: Yussuf Khalil Date: Sat, 25 Nov 2017 23:31:08 +0100 Subject: ALSA: ice1724: Fix resume issues with Prodigy 7.1 HiFi There are two issues after resuming from suspend on the Audiotrak Prodigy 7.1 HiFi: - the output volume is set to 100% - microphone input isn't working anymore This patch fixes these issues by reinitializing both codecs of the device and restoring the previous volumes during resume. Signed-off-by: Yussuf Khalil Signed-off-by: Takashi Iwai --- sound/pci/ice1712/prodigy_hifi.c | 131 ++++++++++++++++++++++++++++++--------- 1 file changed, 102 insertions(+), 29 deletions(-) diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index 2697402b5195..8dabd4d0211d 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c @@ -965,13 +965,32 @@ static int prodigy_hd2_add_controls(struct snd_ice1712 *ice) return 0; } +static void wm8766_init(struct snd_ice1712 *ice) +{ + static unsigned short wm8766_inits[] = { + WM8766_RESET, 0x0000, + WM8766_DAC_CTRL, 0x0120, + WM8766_INT_CTRL, 0x0022, /* I2S Normal Mode, 24 bit */ + WM8766_DAC_CTRL2, 0x0001, + WM8766_DAC_CTRL3, 0x0080, + WM8766_LDA1, 0x0100, + WM8766_LDA2, 0x0100, + WM8766_LDA3, 0x0100, + WM8766_RDA1, 0x0100, + WM8766_RDA2, 0x0100, + WM8766_RDA3, 0x0100, + WM8766_MUTE1, 0x0000, + WM8766_MUTE2, 0x0000, + }; + unsigned int i; -/* - * initialize the chip - */ -static int prodigy_hifi_init(struct snd_ice1712 *ice) + for (i = 0; i < ARRAY_SIZE(wm8766_inits); i += 2) + wm8766_spi_write(ice, wm8766_inits[i], wm8766_inits[i + 1]); +} + +static void wm8776_init(struct snd_ice1712 *ice) { - static unsigned short wm_inits[] = { + static unsigned short wm8776_inits[] = { /* These come first to reduce init pop noise */ WM_ADC_MUX, 0x0003, /* ADC mute */ /* 0x00c0 replaced by 0x0003 */ @@ -982,7 +1001,76 @@ static int prodigy_hifi_init(struct snd_ice1712 *ice) WM_POWERDOWN, 0x0008, /* All power-up except HP */ WM_RESET, 0x0000, /* reset */ }; - static unsigned short wm_inits2[] = { + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(wm8776_inits); i += 2) + wm_put(ice, wm8776_inits[i], wm8776_inits[i + 1]); +} + +#ifdef CONFIG_PM_SLEEP +static int prodigy_hifi_resume(struct snd_ice1712 *ice) +{ + static unsigned short wm8776_reinit_registers[] = { + WM_MASTER_CTRL, + WM_DAC_INT, + WM_ADC_INT, + WM_OUT_MUX, + WM_HP_ATTEN_L, + WM_HP_ATTEN_R, + WM_PHASE_SWAP, + WM_DAC_CTRL2, + WM_ADC_ATTEN_L, + WM_ADC_ATTEN_R, + WM_ALC_CTRL1, + WM_ALC_CTRL2, + WM_ALC_CTRL3, + WM_NOISE_GATE, + WM_ADC_MUX, + /* no DAC attenuation here */ + }; + struct prodigy_hifi_spec *spec = ice->spec; + int i, ch; + + mutex_lock(&ice->gpio_mutex); + + /* reinitialize WM8776 and re-apply old register values */ + wm8776_init(ice); + schedule_timeout_uninterruptible(1); + for (i = 0; i < ARRAY_SIZE(wm8776_reinit_registers); i++) + wm_put(ice, wm8776_reinit_registers[i], + wm_get(ice, wm8776_reinit_registers[i])); + + /* reinitialize WM8766 and re-apply volumes for all DACs */ + wm8766_init(ice); + for (ch = 0; ch < 2; ch++) { + wm_set_vol(ice, WM_DAC_ATTEN_L + ch, + spec->vol[2 + ch], spec->master[ch]); + + wm8766_set_vol(ice, WM8766_LDA1 + ch, + spec->vol[0 + ch], spec->master[ch]); + + wm8766_set_vol(ice, WM8766_LDA2 + ch, + spec->vol[4 + ch], spec->master[ch]); + + wm8766_set_vol(ice, WM8766_LDA3 + ch, + spec->vol[6 + ch], spec->master[ch]); + } + + /* unmute WM8776 DAC */ + wm_put(ice, WM_DAC_MUTE, 0x00); + wm_put(ice, WM_DAC_CTRL1, 0x90); + + mutex_unlock(&ice->gpio_mutex); + return 0; +} +#endif + +/* + * initialize the chip + */ +static int prodigy_hifi_init(struct snd_ice1712 *ice) +{ + static unsigned short wm8776_defaults[] = { WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */ WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */ WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */ @@ -1010,22 +1098,6 @@ static int prodigy_hifi_init(struct snd_ice1712 *ice) WM_DAC_MUTE, 0x0000, /* DAC unmute */ WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */ }; - static unsigned short wm8766_inits[] = { - WM8766_RESET, 0x0000, - WM8766_DAC_CTRL, 0x0120, - WM8766_INT_CTRL, 0x0022, /* I2S Normal Mode, 24 bit */ - WM8766_DAC_CTRL2, 0x0001, - WM8766_DAC_CTRL3, 0x0080, - WM8766_LDA1, 0x0100, - WM8766_LDA2, 0x0100, - WM8766_LDA3, 0x0100, - WM8766_RDA1, 0x0100, - WM8766_RDA2, 0x0100, - WM8766_RDA3, 0x0100, - WM8766_MUTE1, 0x0000, - WM8766_MUTE2, 0x0000, - }; - struct prodigy_hifi_spec *spec; unsigned int i; @@ -1052,16 +1124,17 @@ static int prodigy_hifi_init(struct snd_ice1712 *ice) ice->spec = spec; /* initialize WM8776 codec */ - for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2) - wm_put(ice, wm_inits[i], wm_inits[i+1]); + wm8776_init(ice); schedule_timeout_uninterruptible(1); - for (i = 0; i < ARRAY_SIZE(wm_inits2); i += 2) - wm_put(ice, wm_inits2[i], wm_inits2[i+1]); + for (i = 0; i < ARRAY_SIZE(wm8776_defaults); i += 2) + wm_put(ice, wm8776_defaults[i], wm8776_defaults[i + 1]); - /* initialize WM8766 codec */ - for (i = 0; i < ARRAY_SIZE(wm8766_inits); i += 2) - wm8766_spi_write(ice, wm8766_inits[i], wm8766_inits[i+1]); + wm8766_init(ice); +#ifdef CONFIG_PM_SLEEP + ice->pm_resume = &prodigy_hifi_resume; + ice->pm_suspend_enabled = 1; +#endif return 0; } -- cgit v1.2.3 From df532185e8720baff120f55eb46058d270445d56 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 29 Nov 2017 02:38:27 +0000 Subject: ASoC: soc-core: add missing EXPORT_SYMBOL_GPL() for snd_soc_disconnect_sync Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9047046c749c..345baa4f10c0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1401,6 +1401,7 @@ void snd_soc_disconnect_sync(struct device *dev) snd_card_disconnect_sync(component->card->snd_card); } +EXPORT_SYMBOL_GPL(snd_soc_disconnect_sync); /** * snd_soc_add_dai_link - Add a DAI link dynamically -- cgit v1.2.3 From b2fb31bb7454d5479b1c7214ccd10c1af85a6245 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 29 Nov 2017 03:07:51 +0000 Subject: ASoC: rsnd: TDM 6ch needs 8ch clock for hw refine Renesas sound needs 8ch clock if TDM 6ch mode, and needs 2ch clock for 6ch or 8ch sound if Multi SSI mode. And these are related to before/after CTU (= Channel Transfer Unit). To calculate these we already has rsnd_runtime_channel_for_ssi() which returns runtime necessary channels. But, it based on runtime->channels which is not yet set when hw refine. We need to use hw_params instead of runtime->xxx when hw refine, and it is not needed after runtime was set. This patch adds new hw_params on rsnd_dai_stream, and it will be removed on rsnd_hw_params(). This is very temporary durty code, but it seems no choice at this point. Tested-by: Hiroyuki Yokoyama Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 92 +++++++++++++++++++++++++++++++++++------------- sound/soc/sh/rcar/rsnd.h | 15 ++++++-- 2 files changed, 80 insertions(+), 27 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index bd64dc6ec1c3..d76ad46a6fd9 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -197,16 +197,27 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io) return 0; } -int rsnd_runtime_channel_original(struct rsnd_dai_stream *io) +int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - return runtime->channels; + /* + * params will be added when refine + * see + * __rsnd_soc_hw_rule_rate() + * __rsnd_soc_hw_rule_channels() + */ + if (params) + return params_channels(params); + else + return runtime->channels; } -int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io) +int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params) { - int chan = rsnd_runtime_channel_original(io); + int chan = rsnd_runtime_channel_original_with_params(io, params); struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io); if (ctu_mod) { @@ -219,12 +230,13 @@ int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io) return chan; } -int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io) +int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); int chan = rsnd_io_is_play(io) ? - rsnd_runtime_channel_after_ctu(io) : - rsnd_runtime_channel_original(io); + rsnd_runtime_channel_after_ctu_with_params(io, params) : + rsnd_runtime_channel_original_with_params(io, params); /* Use Multi SSI */ if (rsnd_runtime_is_ssi_multi(io)) @@ -616,8 +628,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: - rsnd_dai_stream_init(io, substream); - ret = rsnd_dai_call(init, io, priv); if (ret < 0) goto dai_trigger_end; @@ -639,7 +649,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, ret |= rsnd_dai_call(quit, io, priv); - rsnd_dai_stream_quit(io); break; default: ret = -EINVAL; @@ -784,8 +793,9 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv, return snd_interval_refine(iv, &p); } -static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) +static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule, + int is_play) { struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); @@ -793,25 +803,37 @@ static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_soc_dai *dai = rule->private; struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; /* * possible sampling rate limitation is same as * 2ch if it supports multi ssi + * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) */ ic = *ic_; - if (1 < rsnd_rdai_ssi_lane_get(rdai)) { - ic.min = 2; - ic.max = 2; - } + ic.min = + ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list, ARRAY_SIZE(rsnd_soc_hw_rate_list), &ic, ir); } +static int rsnd_soc_hw_rule_rate_playback(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + return __rsnd_soc_hw_rule_rate(params, rule, 1); +} + +static int rsnd_soc_hw_rule_rate_capture(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + return __rsnd_soc_hw_rule_rate(params, rule, 0); +} -static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) +static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule, + int is_play) { struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); @@ -819,22 +841,34 @@ static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, struct snd_soc_dai *dai = rule->private; struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; /* * possible sampling rate limitation is same as * 2ch if it supports multi ssi + * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) */ ic = *ic_; - if (1 < rsnd_rdai_ssi_lane_get(rdai)) { - ic.min = 2; - ic.max = 2; - } + ic.min = + ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list, ARRAY_SIZE(rsnd_soc_hw_channels_list), ir, &ic); } +static int rsnd_soc_hw_rule_channels_playback(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + return __rsnd_soc_hw_rule_channels(params, rule, 1); +} + +static int rsnd_soc_hw_rule_channels_capture(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + return __rsnd_soc_hw_rule_channels(params, rule, 0); +} + static const struct snd_pcm_hardware rsnd_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | @@ -859,6 +893,8 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, int ret; int i; + rsnd_dai_stream_init(io, substream); + /* * Channel Limitation * It depends on Platform design @@ -886,11 +922,17 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, * It depends on Clock Master Mode */ if (rsnd_rdai_is_clk_master(rdai)) { + int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - rsnd_soc_hw_rule_rate, dai, + is_play ? rsnd_soc_hw_rule_rate_playback : + rsnd_soc_hw_rule_rate_capture, + dai, SNDRV_PCM_HW_PARAM_CHANNELS, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - rsnd_soc_hw_rule_channels, dai, + is_play ? rsnd_soc_hw_rule_channels_playback : + rsnd_soc_hw_rule_channels_capture, + dai, SNDRV_PCM_HW_PARAM_RATE, -1); } @@ -915,6 +957,8 @@ static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, * call rsnd_dai_call without spinlock */ rsnd_dai_call(nolock_stop, io, priv); + + rsnd_dai_stream_quit(io); } static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 57cd2bc773c2..ad6523595b0a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -399,9 +399,18 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, struct device_node *playback, struct device_node *capture); -int rsnd_runtime_channel_original(struct rsnd_dai_stream *io); -int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io); -int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io); +#define rsnd_runtime_channel_original(io) \ + rsnd_runtime_channel_original_with_params(io, NULL) +int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params); +#define rsnd_runtime_channel_after_ctu(io) \ + rsnd_runtime_channel_after_ctu_with_params(io, NULL) +int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params); +#define rsnd_runtime_channel_for_ssi(io) \ + rsnd_runtime_channel_for_ssi_with_params(io, NULL) +int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params); int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io); int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io); -- cgit v1.2.3 From 65bedda1feec4f57e1322a200853cc29079b01c6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 29 Nov 2017 03:08:35 +0000 Subject: ASoC: rsnd: dma.c: spin lock is no longer needed in IRQ handler DMA handler had needed to calculate pointer before, but it doesn't need now. Thus, we can remove unnecessary spin lock from DMAC handler. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 4d750bdf8e24..41de23417c4a 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -71,25 +71,7 @@ static struct rsnd_mod mem = { static void __rsnd_dmaen_complete(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - bool elapsed = false; - unsigned long flags; - - /* - * Renesas sound Gen1 needs 1 DMAC, - * Gen2 needs 2 DMAC. - * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri. - * But, Audio-DMAC-peri-peri doesn't have interrupt, - * and this driver is assuming that here. - */ - spin_lock_irqsave(&priv->lock, flags); - if (rsnd_io_is_working(io)) - elapsed = true; - - spin_unlock_irqrestore(&priv->lock, flags); - - if (elapsed) rsnd_dai_period_elapsed(io); } -- cgit v1.2.3 From 226d7449135ffc62866c06d73b28cac90b3f31e4 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Fri, 24 Nov 2017 18:08:26 +0800 Subject: ASoC: nau8825: disable crosstalk by default The driver makes the crosstalk funciton disabled by default which can simplify the codec function. The platform may not need this funciton and reduce the potential risk. Therefore, We change the property "nuvoton,crosstalk-bypass" to "nuvoton,crosstalk-enable". The crosstalk measurement is enabled if the property is set. Otherwise, it is disabled. Besides, add more condition in the entry point of the crosstalk sequence to disable the function completely. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/nau8825.txt | 4 ++-- sound/soc/codecs/nau8825.c | 23 ++++++++++++---------- sound/soc/codecs/nau8825.h | 2 +- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/nau8825.txt b/Documentation/devicetree/bindings/sound/nau8825.txt index 2f5e973285a6..d16d96839bcb 100644 --- a/Documentation/devicetree/bindings/sound/nau8825.txt +++ b/Documentation/devicetree/bindings/sound/nau8825.txt @@ -69,7 +69,7 @@ Optional properties: - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms - - nuvoton,crosstalk-bypass: make crosstalk function bypass if set. + - nuvoton,crosstalk-enable: make crosstalk function enable if set. - clocks: list of phandle and clock specifier pairs according to common clock bindings for the clocks described in clock-names @@ -98,7 +98,7 @@ Example: nuvoton,short-key-debounce = <2>; nuvoton,jack-insert-debounce = <7>; nuvoton,jack-eject-debounce = <7>; - nuvoton,crosstalk-bypass; + nuvoton,crosstalk-enable; clock-names = "mclk"; clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>; diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 714ce17da717..d3c1a02f1e15 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -815,11 +815,12 @@ static void nau8825_xtalk_work(struct work_struct *work) static void nau8825_xtalk_cancel(struct nau8825 *nau8825) { - /* If the xtalk_protect is true, that means the process is still - * on going. The driver forces to cancel the cross talk task and + /* If the crosstalk is eanbled and the process is on going, + * the driver forces to cancel the crosstalk task and * restores the configuration to original status. */ - if (nau8825->xtalk_protect) { + if (nau8825->xtalk_enable && nau8825->xtalk_state != + NAU8825_XTALK_DONE) { cancel_work_sync(&nau8825->xtalk_work); nau8825_xtalk_clean(nau8825); } @@ -1686,7 +1687,7 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) } else if (active_irq & NAU8825_HEADSET_COMPLETION_IRQ) { if (nau8825_is_jack_inserted(regmap)) { event |= nau8825_jack_insert(nau8825); - if (!nau8825->xtalk_bypass && !nau8825->high_imped) { + if (nau8825->xtalk_enable && !nau8825->high_imped) { /* Apply the cross talk suppression in the * headset without high impedance. */ @@ -1732,8 +1733,10 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) nau8825->xtalk_event_mask = event_mask; } } else if (active_irq & NAU8825_IMPEDANCE_MEAS_IRQ) { - schedule_work(&nau8825->xtalk_work); - clear_irq = NAU8825_IMPEDANCE_MEAS_IRQ; + if (nau8825->xtalk_enable) { + schedule_work(&nau8825->xtalk_work); + clear_irq = NAU8825_IMPEDANCE_MEAS_IRQ; + } } else if ((active_irq & NAU8825_JACK_INSERTION_IRQ_MASK) == NAU8825_JACK_INSERTION_DETECTED) { /* One more step to check GPIO status directly. Thus, the @@ -2440,8 +2443,8 @@ static void nau8825_print_device_properties(struct nau8825 *nau8825) nau8825->jack_insert_debounce); dev_dbg(dev, "jack-eject-debounce: %d\n", nau8825->jack_eject_debounce); - dev_dbg(dev, "crosstalk-bypass: %d\n", - nau8825->xtalk_bypass); + dev_dbg(dev, "crosstalk-enable: %d\n", + nau8825->xtalk_enable); } static int nau8825_read_device_properties(struct device *dev, @@ -2506,8 +2509,8 @@ static int nau8825_read_device_properties(struct device *dev, &nau8825->jack_eject_debounce); if (ret) nau8825->jack_eject_debounce = 0; - nau8825->xtalk_bypass = device_property_read_bool(dev, - "nuvoton,crosstalk-bypass"); + nau8825->xtalk_enable = device_property_read_bool(dev, + "nuvoton,crosstalk-enable"); nau8825->mclk = devm_clk_get(dev, "mclk"); if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) { diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 8aee5c8647ae..199d6ea4dcdc 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -476,7 +476,7 @@ struct nau8825 { int xtalk_event_mask; bool xtalk_protect; int imp_rms[NAU8825_XTALK_IMM]; - int xtalk_bypass; + int xtalk_enable; }; int nau8825_enable_jack_detect(struct snd_soc_codec *codec, -- cgit v1.2.3 From c997a92a78161af605b314cbe6cf636663999652 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Wed, 22 Nov 2017 00:55:14 +0100 Subject: ASoC: fsl_ssi: call _fsl_ssi_set_dai_fmt() just once in AC'97 mode In AC'97 mode we configure and start SSI RX / TX on probe path via a call to _fsl_ssi_set_dai_fmt() function. We don't need to call this function again later and in fact don't want to do it since this function temporarily sets STCR, SRCR and SCR to some intermediate values. Signed-off-by: Maciej S. Szmigiero Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 9e97a0529f37..939d1b8894dc 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1079,6 +1079,9 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); + if (fsl_ssi_is_ac97(ssi_private)) + return 0; + return _fsl_ssi_set_dai_fmt(cpu_dai->dev, ssi_private, fmt); } -- cgit v1.2.3 From 01ca485171e3253f3aee555437519c0d316d4b0c Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Wed, 22 Nov 2017 00:54:26 +0100 Subject: ASoC: fsl_ssi: only enable proper channel slots in AC'97 mode We need to make sure that only proper channel slots (in SACCST register) are enabled at playback start time since some AC'97 CODECs (like VT1613 on UDOO board) were observed requesting via SLOTREQ spurious ones just after an AC'97 link is started but before the CODEC is configured by its driver. When a bit for some channel slot is set in a SLOTREQ request then SSI sets the relevant bit in SACCST automatically, which then 'sticks' until it is manually unset. The SACCST register is not writable directly, we have to use SACCDIS and SACCEN registers to configure it instead (these aren't normal registers: writing a '1' bit at some position in SACCEN sets the relevant bit in SACCST; SACCDIS operates in a similar way but allows unsetting bits in SACCST). Theoretically, this should be necessary only for the very first playback but since some CODECs are so untrustworthy and extra channel slots enabled mean ruined playback let's play safe here and make sure that no extra slots are enabled in SACCST every time a playback is started. Signed-off-by: Maciej S. Szmigiero Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 52 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 939d1b8894dc..20ef09e1a395 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -577,8 +577,54 @@ static void fsl_ssi_rx_config(struct fsl_ssi_private *ssi_private, bool enable) fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.rx); } +static void fsl_ssi_tx_ac97_saccst_setup(struct fsl_ssi_private *ssi_private) +{ + struct regmap *regs = ssi_private->regs; + + /* no SACC{ST,EN,DIS} regs on imx21-class SSI */ + if (!ssi_private->soc->imx21regs) { + /* + * Note that these below aren't just normal registers. + * They are a way to disable or enable bits in SACCST + * register: + * - writing a '1' bit at some position in SACCEN sets the + * relevant bit in SACCST, + * - writing a '1' bit at some position in SACCDIS unsets + * the relevant bit in SACCST register. + * + * The two writes below first disable all channels slots, + * then enable just slots 3 & 4 ("PCM Playback Left Channel" + * and "PCM Playback Right Channel"). + */ + regmap_write(regs, CCSR_SSI_SACCDIS, 0xff); + regmap_write(regs, CCSR_SSI_SACCEN, 0x300); + } +} + static void fsl_ssi_tx_config(struct fsl_ssi_private *ssi_private, bool enable) { + /* + * Why are we setting up SACCST everytime we are starting a + * playback? + * Some CODECs (like VT1613 CODEC on UDOO board) like to + * (sometimes) set extra bits in their SLOTREQ requests. + * When a bit is set in a SLOTREQ request then SSI sets the + * relevant bit in SACCST automatically (it is enough if a bit was + * set in a SLOTREQ just once, bits in SACCST are 'sticky'). + * If an extra slot gets enabled that's a disaster for playback + * because some of normal left or right channel samples are + * redirected instead to this extra slot. + * + * A workaround implemented in fsl-asoc-card of setting an + * appropriate CODEC register so that slots 3 & 4 (the normal + * stereo playback slots) are used for S/PDIF seems to mostly fix + * this issue on the UDOO board but since this CODEC is so + * untrustworthy let's play safe here and make sure that no extra + * slots are enabled every time a playback is started. + */ + if (enable && fsl_ssi_is_ac97(ssi_private)) + fsl_ssi_tx_ac97_saccst_setup(ssi_private); + fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.tx); } @@ -633,12 +679,6 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private) regmap_write(regs, CCSR_SSI_SACNT, CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV); - /* no SACC{ST,EN,DIS} regs on imx21-class SSI */ - if (!ssi_private->soc->imx21regs) { - regmap_write(regs, CCSR_SSI_SACCDIS, 0xff); - regmap_write(regs, CCSR_SSI_SACCEN, 0x300); - } - /* * Enable SSI, Transmit and Receive. AC97 has to communicate with the * codec before a stream is started. -- cgit v1.2.3 From 494665a0f91b51443ca14ee1dca6d96cfd003b38 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 20 Nov 2017 02:45:36 +0000 Subject: ASoC: soc-utils: add const to dummy_codec Let's align dummy_platform and dummy_codec Signed-off-by: Kuninori Morimoto Reviewed-by: Simon Horman Signed-off-by: Mark Brown --- sound/soc/soc-utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index e30aacbcfc29..bcd3da2739e2 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -288,7 +288,7 @@ static const struct snd_soc_platform_driver dummy_platform = { .ops = &dummy_dma_ops, }; -static struct snd_soc_codec_driver dummy_codec; +static const struct snd_soc_codec_driver dummy_codec; #define STUB_RATES SNDRV_PCM_RATE_8000_192000 #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ -- cgit v1.2.3 From 10582635dc8f4f99448c5dcddac38cc18a72dfde Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 27 Nov 2017 23:34:44 +0100 Subject: ASoC: fsl_ssi: add 20-bit sample format for AC'97 and use it for capture When testing AC'97 capture on UDOO board (currently the only user of fsl_ssi driver in the AC'97 mode) it become obvious that there is a massive distortion above certain, small input signal. This problem has been traced to silicon errata ERR003778: "In AC97, 16-bit mode, received data is shifted by 4-bit locations" that has "No fix scheduled". This errata suggests a workaround of doing a 4-bit shift back in SDMA script for this specific operation mode, however our SDMA scripts are shared between various SoC peripherals so we can't really modify them. There is a simple way to avoid this problem, however, that is to disallow recording in 16-bit mode and only support it in AC'97-native 20-bit mode. We have to use a 4-byte format for this since SSI FIFOs do not allow 3-byte accesses (and these aren't supported by imx-sdma driver anyway). With this change the capture distortion is gone. We can also add this format as an additional one supported for playback, using this opportunity to make sure that we use CPU-endian-native formats in AC'97 mode as we already do in I2S mode. There is no problem in using different bit widths in playback and capture in AC'97 mode so allow this, too. Signed-off-by: Maciej S. Szmigiero Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 20ef09e1a395..c350117c8e31 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1278,14 +1278,15 @@ static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S20, }, .capture = { .stream_name = "AC97 Capture", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + /* 16-bit capture is broken (errata ERR003778) */ + .formats = SNDRV_PCM_FMTBIT_S20, }, .ops = &fsl_ssi_dai_ops, }; @@ -1557,11 +1558,12 @@ static int fsl_ssi_probe(struct platform_device *pdev) /* Are the RX and the TX clocks locked? */ if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) { - if (!fsl_ssi_is_ac97(ssi_private)) + if (!fsl_ssi_is_ac97(ssi_private)) { ssi_private->cpu_dai_drv.symmetric_rates = 1; + ssi_private->cpu_dai_drv.symmetric_samplebits = 1; + } ssi_private->cpu_dai_drv.symmetric_channels = 1; - ssi_private->cpu_dai_drv.symmetric_samplebits = 1; } /* Determine the FIFO depth. */ -- cgit v1.2.3 From bc2bd45b1f7f35b80335367f682c0ae5b2f37911 Mon Sep 17 00:00:00 2001 From: Sriram Periyasamy Date: Wed, 22 Nov 2017 17:39:46 +0530 Subject: ASoC: Intel: Skylake: Parse nhlt and register clock device When NHLT endpoint is present for a SSP then we create clock for that SSP. MCLK is consistent across endpoints and configuration for an SSP, so query only for first endpoint for an SSP. For SCLK/SCLKFS, the best fit is queried from the NHLT configurations which matches the clock rate requested. Best fit is decided based on below: 1. If rate matches with multiple configurations, then the first configuration is selected. 2. If for a selected fs and bits_per_sample, there are multiple endpoint configuration match, then the configuration with max number of channels is selected. So, the user has to set the rate which fits max number of channels So we create a platform device and pass clock information parsed as platform data. Signed-off-by: Sriram Periyasamy Signed-off-by: Jaikrishna Nemallapudi Signed-off-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-i2s.h | 64 ++++++++++++++ sound/soc/intel/skylake/skl-nhlt.c | 155 ++++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-ssp-clk.h | 79 +++++++++++++++++ sound/soc/intel/skylake/skl.c | 93 ++++++++++++++++++++ sound/soc/intel/skylake/skl.h | 4 + 5 files changed, 395 insertions(+) create mode 100644 sound/soc/intel/skylake/skl-i2s.h create mode 100644 sound/soc/intel/skylake/skl-ssp-clk.h diff --git a/sound/soc/intel/skylake/skl-i2s.h b/sound/soc/intel/skylake/skl-i2s.h new file mode 100644 index 000000000000..dcf819bc688f --- /dev/null +++ b/sound/soc/intel/skylake/skl-i2s.h @@ -0,0 +1,64 @@ +/* + * skl-i2s.h - i2s blob mapping + * + * Copyright (C) 2017 Intel Corp + * Author: Subhransu S. Prusty < subhransu.s.prusty@intel.com> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ + +#ifndef __SOUND_SOC_SKL_I2S_H +#define __SOUND_SOC_SKL_I2S_H + +#define SKL_I2S_MAX_TIME_SLOTS 8 +#define SKL_MCLK_DIV_CLK_SRC_MASK GENMASK(17, 16) + +#define SKL_MNDSS_DIV_CLK_SRC_MASK GENMASK(21, 20) +#define SKL_SHIFT(x) (ffs(x) - 1) +#define SKL_MCLK_DIV_RATIO_MASK GENMASK(11, 0) + +struct skl_i2s_config { + u32 ssc0; + u32 ssc1; + u32 sscto; + u32 sspsp; + u32 sstsa; + u32 ssrsa; + u32 ssc2; + u32 sspsp2; + u32 ssc3; + u32 ssioc; +} __packed; + +struct skl_i2s_config_mclk { + u32 mdivctrl; + u32 mdivr; +}; + +/** + * struct skl_i2s_config_blob_legacy - Structure defines I2S Gateway + * configuration legacy blob + * + * @gtw_attr: Gateway attribute for the I2S Gateway + * @tdm_ts_group: TDM slot mapping against channels in the Gateway. + * @i2s_cfg: I2S HW registers + * @mclk: MCLK clock source and divider values + */ +struct skl_i2s_config_blob_legacy { + u32 gtw_attr; + u32 tdm_ts_group[SKL_I2S_MAX_TIME_SLOTS]; + struct skl_i2s_config i2s_cfg; + struct skl_i2s_config_mclk mclk; +}; + +#endif /* __SOUND_SOC_SKL_I2S_H */ diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index e7d766d56c8e..4d2136c0389a 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -19,6 +19,7 @@ */ #include #include "skl.h" +#include "skl-i2s.h" /* Unique identification for getting NHLT blobs */ static guid_t osc_guid = @@ -262,3 +263,157 @@ void skl_nhlt_remove_sysfs(struct skl *skl) sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr); } + +/* + * Queries NHLT for all the fmt configuration for a particular endpoint and + * stores all possible rates supported in a rate table for the corresponding + * sclk/sclkfs. + */ +void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, + struct nhlt_fmt *fmt, u8 id) +{ + struct skl_i2s_config_blob_legacy *i2s_config; + struct skl_clk_parent_src *parent; + struct skl_ssp_clk *sclk, *sclkfs; + struct nhlt_fmt_cfg *fmt_cfg; + struct wav_fmt_ext *wav_fmt; + unsigned long rate = 0; + bool present = false; + int rate_index = 0; + u16 channels, bps; + u8 clk_src; + int i, j; + u32 fs; + + sclk = &ssp_clks[SKL_SCLK_OFS]; + sclkfs = &ssp_clks[SKL_SCLKFS_OFS]; + + if (fmt->fmt_count == 0) + return; + + for (i = 0; i < fmt->fmt_count; i++) { + fmt_cfg = &fmt->fmt_config[i]; + wav_fmt = &fmt_cfg->fmt_ext; + + channels = wav_fmt->fmt.channels; + bps = wav_fmt->fmt.bits_per_sample; + fs = wav_fmt->fmt.samples_per_sec; + + /* + * In case of TDM configuration on a ssp, there can + * be more than one blob in which channel masks are + * different for each usecase for a specific rate and bps. + * But the sclk rate will be generated for the total + * number of channels used for that endpoint. + * + * So for the given fs and bps, choose blob which has + * the superset of all channels for that endpoint and + * derive the rate. + */ + for (j = i; j < fmt->fmt_count; j++) { + fmt_cfg = &fmt->fmt_config[j]; + wav_fmt = &fmt_cfg->fmt_ext; + if ((fs == wav_fmt->fmt.samples_per_sec) && + (bps == wav_fmt->fmt.bits_per_sample)) + channels = max_t(u16, channels, + wav_fmt->fmt.channels); + } + + rate = channels * bps * fs; + + /* check if the rate is added already to the given SSP's sclk */ + for (j = 0; (sclk[id].rate_cfg[j].rate != 0) && + (j < SKL_MAX_CLK_RATES); j++) { + if (sclk[id].rate_cfg[j].rate == rate) { + present = true; + break; + } + } + + /* Fill rate and parent for sclk/sclkfs */ + if (!present) { + /* MCLK Divider Source Select */ + i2s_config = (struct skl_i2s_config_blob_legacy *) + fmt->fmt_config[0].config.caps; + clk_src = ((i2s_config->mclk.mdivctrl) + & SKL_MNDSS_DIV_CLK_SRC_MASK) >> + SKL_SHIFT(SKL_MNDSS_DIV_CLK_SRC_MASK); + + parent = skl_get_parent_clk(clk_src); + + /* + * Do not copy the config data if there is no parent + * clock available for this clock source select + */ + if (!parent) + continue; + + sclk[id].rate_cfg[rate_index].rate = rate; + sclk[id].rate_cfg[rate_index].config = fmt_cfg; + sclkfs[id].rate_cfg[rate_index].rate = rate; + sclkfs[id].rate_cfg[rate_index].config = fmt_cfg; + sclk[id].parent_name = parent->name; + sclkfs[id].parent_name = parent->name; + + rate_index++; + } + } +} + +void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk, + struct nhlt_fmt *fmt, u8 id) +{ + struct skl_i2s_config_blob_legacy *i2s_config; + struct nhlt_specific_cfg *fmt_cfg; + struct skl_clk_parent_src *parent; + u32 clkdiv, div_ratio; + u8 clk_src; + + fmt_cfg = &fmt->fmt_config[0].config; + i2s_config = (struct skl_i2s_config_blob_legacy *)fmt_cfg->caps; + + /* MCLK Divider Source Select */ + clk_src = ((i2s_config->mclk.mdivctrl) & SKL_MCLK_DIV_CLK_SRC_MASK) >> + SKL_SHIFT(SKL_MCLK_DIV_CLK_SRC_MASK); + + clkdiv = i2s_config->mclk.mdivr & SKL_MCLK_DIV_RATIO_MASK; + + /* bypass divider */ + div_ratio = 1; + + if (clkdiv != SKL_MCLK_DIV_RATIO_MASK) + /* Divider is 2 + clkdiv */ + div_ratio = clkdiv + 2; + + /* Calculate MCLK rate from source using div value */ + parent = skl_get_parent_clk(clk_src); + if (!parent) + return; + + mclk[id].rate_cfg[0].rate = parent->rate/div_ratio; + mclk[id].rate_cfg[0].config = &fmt->fmt_config[0]; + mclk[id].parent_name = parent->name; +} + +void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks) +{ + struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; + struct nhlt_endpoint *epnt; + struct nhlt_fmt *fmt; + int i; + u8 id; + + epnt = (struct nhlt_endpoint *)nhlt->desc; + for (i = 0; i < nhlt->endpoint_count; i++) { + if (epnt->linktype == NHLT_LINK_SSP) { + id = epnt->virtual_bus_id; + + fmt = (struct nhlt_fmt *)(epnt->config.caps + + epnt->config.size); + + skl_get_ssp_clks(skl, ssp_clks, fmt, id); + skl_get_mclk(skl, ssp_clks, fmt, id); + } + epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); + } +} diff --git a/sound/soc/intel/skylake/skl-ssp-clk.h b/sound/soc/intel/skylake/skl-ssp-clk.h new file mode 100644 index 000000000000..c9ea84004260 --- /dev/null +++ b/sound/soc/intel/skylake/skl-ssp-clk.h @@ -0,0 +1,79 @@ +/* + * skl-ssp-clk.h - Skylake ssp clock information and ipc structure + * + * Copyright (C) 2017 Intel Corp + * Author: Jaikrishna Nemallapudi + * Author: Subhransu S. Prusty + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ + +#ifndef SOUND_SOC_SKL_SSP_CLK_H +#define SOUND_SOC_SKL_SSP_CLK_H + +#define SKL_MAX_SSP 6 +/* xtal/cardinal/pll, parent of ssp clocks and mclk */ +#define SKL_MAX_CLK_SRC 3 +#define SKL_MAX_SSP_CLK_TYPES 3 /* mclk, sclk, sclkfs */ + +#define SKL_MAX_CLK_CNT (SKL_MAX_SSP * SKL_MAX_SSP_CLK_TYPES) + +/* Max number of configurations supported for each clock */ +#define SKL_MAX_CLK_RATES 10 + +#define SKL_SCLK_OFS SKL_MAX_SSP +#define SKL_SCLKFS_OFS (SKL_SCLK_OFS + SKL_MAX_SSP) + +enum skl_clk_type { + SKL_MCLK, + SKL_SCLK, + SKL_SCLK_FS, +}; + +enum skl_clk_src_type { + SKL_XTAL, + SKL_CARDINAL, + SKL_PLL, +}; + +struct skl_clk_parent_src { + u8 clk_id; + const char *name; + unsigned long rate; + const char *parent_name; +}; + +struct skl_clk_rate_cfg_table { + unsigned long rate; + void *config; +}; + +/* + * rate for mclk will be in rates[0]. For sclk and sclkfs, rates[] store + * all possible clocks ssp can generate for that platform. + */ +struct skl_ssp_clk { + const char *name; + const char *parent_name; + struct skl_clk_rate_cfg_table rate_cfg[SKL_MAX_CLK_RATES]; +}; + +struct skl_clk_pdata { + struct skl_clk_parent_src *parent_clks; + int num_clks; + struct skl_ssp_clk *ssp_clks; + void *pvt_data; +}; + +#endif /* SOUND_SOC_SKL_SSP_CLK_H */ diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index acb0ab470ca6..63e5456ef401 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -436,6 +436,23 @@ static int skl_free(struct hdac_ext_bus *ebus) return 0; } +/* + * For each ssp there are 3 clocks (mclk/sclk/sclkfs). + * e.g. for ssp0, clocks will be named as + * "ssp0_mclk", "ssp0_sclk", "ssp0_sclkfs" + * So for skl+, there are 6 ssps, so 18 clocks will be created. + */ +static struct skl_ssp_clk skl_ssp_clks[] = { + {.name = "ssp0_mclk"}, {.name = "ssp1_mclk"}, {.name = "ssp2_mclk"}, + {.name = "ssp3_mclk"}, {.name = "ssp4_mclk"}, {.name = "ssp5_mclk"}, + {.name = "ssp0_sclk"}, {.name = "ssp1_sclk"}, {.name = "ssp2_sclk"}, + {.name = "ssp3_sclk"}, {.name = "ssp4_sclk"}, {.name = "ssp5_sclk"}, + {.name = "ssp0_sclkfs"}, {.name = "ssp1_sclkfs"}, + {.name = "ssp2_sclkfs"}, + {.name = "ssp3_sclkfs"}, {.name = "ssp4_sclkfs"}, + {.name = "ssp5_sclkfs"}, +}; + static int skl_machine_device_register(struct skl *skl, void *driver_data) { struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); @@ -510,6 +527,74 @@ static void skl_dmic_device_unregister(struct skl *skl) platform_device_unregister(skl->dmic_dev); } +static struct skl_clk_parent_src skl_clk_src[] = { + { .clk_id = SKL_XTAL, .name = "xtal" }, + { .clk_id = SKL_CARDINAL, .name = "cardinal", .rate = 24576000 }, + { .clk_id = SKL_PLL, .name = "pll", .rate = 96000000 }, +}; + +struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(skl_clk_src); i++) { + if (skl_clk_src[i].clk_id == clk_id) + return &skl_clk_src[i]; + } + + return NULL; +} + +void init_skl_xtal_rate(int pci_id) +{ + switch (pci_id) { + case 0x9d70: + case 0x9d71: + skl_clk_src[0].rate = 24000000; + return; + + default: + skl_clk_src[0].rate = 19200000; + return; + } +} + +static int skl_clock_device_register(struct skl *skl) +{ + struct platform_device_info pdevinfo = {NULL}; + struct skl_clk_pdata *clk_pdata; + + clk_pdata = devm_kzalloc(&skl->pci->dev, sizeof(*clk_pdata), + GFP_KERNEL); + if (!clk_pdata) + return -ENOMEM; + + init_skl_xtal_rate(skl->pci->device); + + clk_pdata->parent_clks = skl_clk_src; + clk_pdata->ssp_clks = skl_ssp_clks; + clk_pdata->num_clks = ARRAY_SIZE(skl_ssp_clks); + + /* Query NHLT to fill the rates and parent */ + skl_get_clks(skl, clk_pdata->ssp_clks); + clk_pdata->pvt_data = skl; + + /* Register Platform device */ + pdevinfo.parent = &skl->pci->dev; + pdevinfo.id = -1; + pdevinfo.name = "skl-ssp-clk"; + pdevinfo.data = clk_pdata; + pdevinfo.size_data = sizeof(*clk_pdata); + skl->clk_dev = platform_device_register_full(&pdevinfo); + return PTR_ERR_OR_ZERO(skl->clk_dev); +} + +static void skl_clock_device_unregister(struct skl *skl) +{ + if (skl->clk_dev) + platform_device_unregister(skl->clk_dev); +} + /* * Probe the given codec address */ @@ -792,6 +877,11 @@ static int skl_probe(struct pci_dev *pci, /* check if dsp is there */ if (bus->ppcap) { + /* create device for dsp clk */ + err = skl_clock_device_register(skl); + if (err < 0) + goto out_clk_free; + err = skl_machine_device_register(skl, (void *)pci_id->driver_data); if (err < 0) @@ -823,6 +913,8 @@ out_dsp_free: skl_free_dsp(skl); out_mach_free: skl_machine_device_unregister(skl); +out_clk_free: + skl_clock_device_unregister(skl); out_nhlt_free: skl_nhlt_free(skl->nhlt); out_free: @@ -873,6 +965,7 @@ static void skl_remove(struct pci_dev *pci) skl_free_dsp(skl); skl_machine_device_unregister(skl); skl_dmic_device_unregister(skl); + skl_clock_device_unregister(skl); skl_nhlt_remove_sysfs(skl); skl_nhlt_free(skl->nhlt); skl_free(ebus); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index e00cde8200dd..554ad6b5a823 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -25,6 +25,7 @@ #include #include #include "skl-nhlt.h" +#include "skl-ssp-clk.h" #define SKL_SUSPEND_DELAY 2000 @@ -52,6 +53,7 @@ struct skl { unsigned int init_done:1; /* delayed init status */ struct platform_device *dmic_dev; struct platform_device *i2s_dev; + struct platform_device *clk_dev; struct snd_soc_platform *platform; struct snd_soc_dai_driver *dais; @@ -125,6 +127,8 @@ const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); void skl_update_d0i3c(struct device *dev, bool enable); int skl_nhlt_create_sysfs(struct skl *skl); void skl_nhlt_remove_sysfs(struct skl *skl); +void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks); +struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id); struct skl_module_cfg; -- cgit v1.2.3 From ea261bd02a671e2dd60380053dddffedab81644d Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Tue, 21 Nov 2017 17:15:45 +0000 Subject: ASoC: intel: byt: Introduce new map for dual mics The RT5651 codec has 3 analog inputs. Some laptops have two different internal analog microphones on the external case. Add a new custom quirk mapping the two internal mics on IN1P / IN2P, leaving the headset mic on IN3P. Signed-off-by: Carlo Caione Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index d955836c6870..e3d5e6ea707f 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -38,6 +38,7 @@ enum { BYT_RT5651_DMIC_MAP, BYT_RT5651_IN1_MAP, BYT_RT5651_IN2_MAP, + BYT_RT5651_IN1_IN2_MAP, }; #define BYT_RT5651_MAP(quirk) ((quirk) & GENMASK(7, 0)) @@ -171,6 +172,13 @@ static const struct snd_soc_dapm_route byt_rt5651_intmic_in2_map[] = { {"IN2P", NULL, "Internal Mic"}, }; +static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_in2_map[] = { + {"Internal Mic", NULL, "micbias1"}, + {"IN1P", NULL, "Internal Mic"}, + {"IN2P", NULL, "Internal Mic"}, + {"IN3P", NULL, "Headset Mic"}, +}; + static const struct snd_kcontrol_new byt_rt5651_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), @@ -281,6 +289,10 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) custom_map = byt_rt5651_intmic_in2_map; num_routes = ARRAY_SIZE(byt_rt5651_intmic_in2_map); break; + case BYT_RT5651_IN1_IN2_MAP: + custom_map = byt_rt5651_intmic_in1_in2_map; + num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_in2_map); + break; default: custom_map = byt_rt5651_intmic_dmic_map; num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic_map); -- cgit v1.2.3 From 56fa898be862053327b2ff8abfa0a6e7f350f81d Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Tue, 21 Nov 2017 17:15:46 +0000 Subject: ASoC: intel: byt: Fix quirk for KIANO laptop This laptop has actually two different analog mics, no just one. Fix the quirk to reflect the correct configuration. Signed-off-by: Carlo Caione Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index e3d5e6ea707f..488ec48f296a 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -264,7 +264,7 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "KIANO"), DMI_MATCH(DMI_PRODUCT_NAME, "KIANO SlimNote 14.2"), }, - .driver_data = (void *)(BYT_RT5651_IN2_MAP), + .driver_data = (void *)(BYT_RT5651_IN1_IN2_MAP), }, {} }; -- cgit v1.2.3 From f00e0030bcbf49936d265330f6e0b8c739ad90c3 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 11:13:52 -0600 Subject: ASoC: tlv320aic31xx: Rename property for reset GPIO The property used to specify a GPIO intended for reset is "reset-gpios", but this binding uses "gpio-reset". It is not compatible with newer methods used to fetch GPIO pins and to prevent the spread of this error to other bindings let's rename to be more standard. We also standardize the pin as active-low, different device trees have marked the GPIO different ways, luckily the driver currently uses the low-level GPIO set function which does not respect the active-low flag, but future changes may change this. This is an active-low reset, mark it as such. Lastly, add an example of use for this property. [Rewrote the title & first paragraph of the commit message for clarity -- broonie] Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/tlv320aic31xx.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt index 6fbba562eaa7..5b3c33bb99e5 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt @@ -22,7 +22,7 @@ Required properties: Optional properties: -- gpio-reset - gpio pin number used for codec reset +- reset-gpios - GPIO specification for the active low RESET input. - ai31xx-micbias-vg - MicBias Voltage setting 1 or MICBIAS_2_0V - MICBIAS output is powered to 2.0V 2 or MICBIAS_2_5V - MICBIAS output is powered to 2.5V @@ -30,6 +30,10 @@ Optional properties: If this node is not mentioned or if the value is unknown, then micbias is set to 2.0V. +Deprecated properties: + +- gpio-reset - gpio pin number used for codec reset + CODEC output pins: * HPL * HPR @@ -48,6 +52,7 @@ CODEC input pins: The pins can be used in referring sound node's audio-routing property. Example: +#include #include tlv320aic31xx: tlv320aic31xx@18 { @@ -56,6 +61,8 @@ tlv320aic31xx: tlv320aic31xx@18 { ai31xx-micbias-vg = ; + reset-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>; + HPVDD-supply = <®ulator>; SPRVDD-supply = <®ulator>; SPLVDD-supply = <®ulator>; -- cgit v1.2.3 From a825f31f93281bbe7126b25801deb476d07aaf82 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 11:13:54 -0600 Subject: ASoC: tlv320aic31xx: Use standard reset GPIO OF name The correct DT property for specifying a GPIO used for reset is "reset-gpios", fix this here. [Retitled for accuracy -- broonie] Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index e2862372c26e..4837f25b0760 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1279,9 +1279,16 @@ static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx) aic31xx->pdata.micbias_vg = MICBIAS_2_0V; } - ret = of_get_named_gpio(np, "gpio-reset", 0); - if (ret > 0) + ret = of_get_named_gpio(np, "reset-gpios", 0); + if (ret > 0) { aic31xx->pdata.gpio_reset = ret; + } else { + ret = of_get_named_gpio(np, "gpio-reset", 0); + if (ret > 0) { + dev_warn(aic31xx->dev, "Using deprecated property \"gpio-reset\", please update your DT"); + aic31xx->pdata.gpio_reset = ret; + } + } } #else /* CONFIG_OF */ static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx) -- cgit v1.2.3 From 943293232ca45988ba0aa693b51025c58e1189ca Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 11:13:53 -0600 Subject: ASoC: tlv320aic3x: Rename property for reset GPIO The property used to specify a GPIO intended for reset is "reset-gpios", but this binding uses "gpio-reset". It is not compatible with newer methods used to fetch GPIO pins and to prevent the spread of this error to other bindings let's rename to be more standard. We also standardize the pin as active-low, different device trees have marked the GPIO different ways, luckily the driver currently uses the low-level GPIO set function which does not respect the active-low flag, but future changes may change this. This is an active-low reset, mark it as such. Lastly, add an example of use for this property. [Rewrote title & first paragraph for clarity & accuracy -- broonie] Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/tlv320aic3x.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt index ba5b45c483f5..9796c4639262 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt @@ -17,7 +17,7 @@ Required properties: Optional properties: -- gpio-reset - gpio pin number used for codec reset +- reset-gpios - GPIO specification for the active low RESET input. - ai3x-gpio-func - - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality - Not supported on tlv320aic3104 - ai3x-micbias-vg - MicBias Voltage required. @@ -34,6 +34,10 @@ Optional properties: - AVDD-supply, IOVDD-supply, DRVDD-supply, DVDD-supply : power supplies for the device as covered in Documentation/devicetree/bindings/regulator/regulator.txt +Deprecated properties: + +- gpio-reset - gpio pin number used for codec reset + CODEC output pins: * LLOUT * RLOUT @@ -61,10 +65,14 @@ The pins can be used in referring sound node's audio-routing property. Example: +#include + tlv320aic3x: tlv320aic3x@1b { compatible = "ti,tlv320aic3x"; reg = <0x1b>; + reset-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>; + AVDD-supply = <®ulator>; IOVDD-supply = <®ulator>; DRVDD-supply = <®ulator>; -- cgit v1.2.3 From 025f8449818c46770f5652a0263f8cfb89d01455 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 11:13:55 -0600 Subject: ASoC: tlv320aic3x: Use standard reset GPIO OF name The correct DT property for specifying a GPIO used for reset is "reset-gpios", fix this here. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 06f92571eba4..b751cad545da 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1804,11 +1804,18 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, if (!ai3x_setup) return -ENOMEM; - ret = of_get_named_gpio(np, "gpio-reset", 0); - if (ret >= 0) + ret = of_get_named_gpio(np, "reset-gpios", 0); + if (ret >= 0) { aic3x->gpio_reset = ret; - else - aic3x->gpio_reset = -1; + } else { + ret = of_get_named_gpio(np, "gpio-reset", 0); + if (ret > 0) { + dev_warn(&i2c->dev, "Using deprecated property \"gpio-reset\", please update your DT"); + aic3x->gpio_reset = ret; + } else { + aic3x->gpio_reset = -1; + } + } if (of_property_read_u32_array(np, "ai3x-gpio-func", ai3x_setup->gpio_func, 2) >= 0) { -- cgit v1.2.3 From e3fee43a968fd39dcc56be3757fcdfe250964125 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Thu, 30 Nov 2017 10:13:17 +0800 Subject: ASoC: nau8825: set clear_irq when imm IRQ happened Although the crosstalk is disabled, it is better to set clear_irq properly when the impedance measurement interrupt happens. It can avoid that the driver clears other IRQs by accident if the active_irq has another IRQ events. Signed-off-by: John Hsu Reviewed-by: Wu-Cheng Li Tested-by: Wu-Cheng Li Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index d3c1a02f1e15..603cd72c2a25 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -1733,10 +1733,9 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) nau8825->xtalk_event_mask = event_mask; } } else if (active_irq & NAU8825_IMPEDANCE_MEAS_IRQ) { - if (nau8825->xtalk_enable) { + if (nau8825->xtalk_enable) schedule_work(&nau8825->xtalk_work); - clear_irq = NAU8825_IMPEDANCE_MEAS_IRQ; - } + clear_irq = NAU8825_IMPEDANCE_MEAS_IRQ; } else if ((active_irq & NAU8825_JACK_INSERTION_IRQ_MASK) == NAU8825_JACK_INSERTION_DETECTED) { /* One more step to check GPIO status directly. Thus, the -- cgit v1.2.3 From b1c52b7e7cc6a57128869008b84d98a4de78fe2d Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 15:32:42 -0600 Subject: ASoC: tlv320aic31xx: File header and copyright cleanup Fix header copyright tags, while we are here, also switch to SPDX and fixup MODULE tags to match. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 26 +++++++++----------------- sound/soc/codecs/tlv320aic31xx.h | 15 ++++----------- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 4837f25b0760..b98d9b1f216f 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1,22 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * ALSA SoC TLV320AIC31XX codec driver + * ALSA SoC TLV320AIC31xx CODEC Driver * - * Copyright (C) 2014 Texas Instruments, Inc. - * - * Author: Jyri Sarha + * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Jyri Sarha * * Based on ground work by: Ajit Kulkarni * - * This package is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * THIS PACKAGE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * The TLV320AIC31xx series of audio codec is a low-power, highly integrated - * high performance codec which provides a stereo DAC, a mono ADC, + * The TLV320AIC31xx series of audio codecs are low-power, highly integrated + * high performance codecs which provides a stereo DAC, a mono ADC, * and mono/stereo Class-D speaker driver. */ @@ -1414,6 +1406,6 @@ static struct i2c_driver aic31xx_i2c_driver = { module_i2c_driver(aic31xx_i2c_driver); -MODULE_DESCRIPTION("ASoC TLV320AIC3111 codec driver"); -MODULE_AUTHOR("Jyri Sarha"); -MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jyri Sarha "); +MODULE_DESCRIPTION("ASoC TLV320AIC31xx CODEC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 730fb2058869..a9ea2f99eba0 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -1,17 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * ALSA SoC TLV320AIC31XX codec driver - * - * Copyright (C) 2013 Texas Instruments, Inc. - * - * This package is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * ALSA SoC TLV320AIC31xx CODEC Driver Definitions * + * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/ */ + #ifndef _TLV320AIC31XX_H #define _TLV320AIC31XX_H -- cgit v1.2.3 From c7734e8e7eddf065c15e865b8de4224b01f03409 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 15:32:43 -0600 Subject: ASoC: tlv320aic31xx: Change aic31xx_power_off return type to void The return value is not checked, and even if it was there is nothing we could do about it and messages are already printed. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index b98d9b1f216f..0563a49cc5e4 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1081,16 +1081,13 @@ static int aic31xx_power_on(struct snd_soc_codec *codec) return 0; } -static int aic31xx_power_off(struct snd_soc_codec *codec) +static void aic31xx_power_off(struct snd_soc_codec *codec) { struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); - int ret = 0; regcache_cache_only(aic31xx->regmap, true); - ret = regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies), - aic31xx->supplies); - - return ret; + regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies), + aic31xx->supplies); } static int aic31xx_set_bias_level(struct snd_soc_codec *codec, -- cgit v1.2.3 From 09303601bacda714220048a61f6864f88594b231 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 15:32:44 -0600 Subject: ASoC: tlv320aic31xx: Move ACPI table next to OF table Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 0563a49cc5e4..d974e8651e30 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1285,6 +1285,14 @@ static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx) } #endif /* CONFIG_OF */ +#ifdef CONFIG_ACPI +static const struct acpi_device_id aic31xx_acpi_match[] = { + { "10TI3100", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match); +#endif + static int aic31xx_device_init(struct aic31xx_priv *aic31xx) { int ret, i; @@ -1382,14 +1390,6 @@ static const struct i2c_device_id aic31xx_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); -#ifdef CONFIG_ACPI -static const struct acpi_device_id aic31xx_acpi_match[] = { - { "10TI3100", 0 }, - { } -}; -MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match); -#endif - static struct i2c_driver aic31xx_i2c_driver = { .driver = { .name = "tlv320aic31xx-codec", -- cgit v1.2.3 From 108884e6c5aa731c6704000e27444d51d090078b Mon Sep 17 00:00:00 2001 From: Tamaki Nishino Date: Thu, 30 Nov 2017 20:27:52 +0900 Subject: ALSA: usb-audio: Change the semantics of the enable option This patch changes the semantics of the enable option for snd-usb-audio in order to allow users to disable a device specified by either or both of the vendor id and the product id. Signed-off-by: Tamaki Nishino Signed-off-by: Takashi Iwai --- sound/usb/card.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index 23d1d23aefec..8018d56cfecc 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -585,15 +585,24 @@ static int usb_audio_probe(struct usb_interface *intf, * now look for an empty slot and create a new card instance */ for (i = 0; i < SNDRV_CARDS; i++) - if (enable[i] && ! usb_chip[i] && + if (!usb_chip[i] && (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && (pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) { - err = snd_usb_audio_create(intf, dev, i, quirk, - id, &chip); - if (err < 0) + if (enable[i]) { + err = snd_usb_audio_create(intf, dev, i, quirk, + id, &chip); + if (err < 0) + goto __error; + chip->pm_intf = intf; + break; + } else if (vid[i] != -1 || pid[i] != -1) { + dev_info(&dev->dev, + "device (%04x:%04x) is disabled\n", + USB_ID_VENDOR(id), + USB_ID_PRODUCT(id)); + err = -ENOENT; goto __error; - chip->pm_intf = intf; - break; + } } if (!chip) { dev_err(&dev->dev, "no available usb audio device\n"); -- cgit v1.2.3 From b09b1c3bc0b7f391d00ea9e0c5970b1bbbe86eca Mon Sep 17 00:00:00 2001 From: "Ughreja, Rakesh A" Date: Fri, 1 Dec 2017 14:43:17 +0530 Subject: ASoC: hdac_hdmi: introduce macro to access HDMI private data This patch replaces the direct access of HDMI private data with macro hdev_to_hdmi_priv in order to prepare the code to remove hdac_ext_device usage in the subsequent patch. Signed-off-by: Rakesh Ughreja Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 68 +++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index f3b4f4dfae6a..05af2299579b 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -138,6 +138,8 @@ struct hdac_hdmi_priv { struct hdac_hdmi_drv_data *drv_data; }; +#define hdev_to_hdmi_priv(_hdev) ((to_ehdac_device(_hdev))->private_data) + static struct hdac_hdmi_pcm * hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi, struct hdac_hdmi_cvt *cvt) @@ -351,7 +353,7 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, struct hdmi_audio_infoframe frame; struct hdac_hdmi_pin *pin = port->pin; struct dp_audio_infoframe dp_ai; - struct hdac_hdmi_priv *hdmi = hdac->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&hdac->hdac); struct hdac_hdmi_cvt *cvt = pcm->cvt; u8 *dip; int ret; @@ -433,7 +435,7 @@ static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai, int slots, int slot_width) { struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_pcm *pcm; @@ -453,7 +455,7 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai) { struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdac->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&hdac->hdac); struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_port *port; struct hdac_hdmi_pcm *pcm; @@ -566,7 +568,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdac->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&hdac->hdac); struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_cvt *cvt; struct hdac_hdmi_port *port; @@ -609,7 +611,7 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdac->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&hdac->hdac); struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_pcm *pcm; @@ -633,8 +635,7 @@ static int hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) { unsigned int chans; - struct hdac_ext_device *edev = to_ehdac_device(hdac); - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); int err; chans = get_wcaps(hdac, cvt->nid); @@ -696,7 +697,7 @@ static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, struct hdac_hdmi_port *port) { - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_pcm *pcm = NULL; struct hdac_hdmi_port *p; @@ -782,7 +783,7 @@ static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w, { struct hdac_hdmi_cvt *cvt = w->priv; struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_pcm *pcm; dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", @@ -864,7 +865,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_context *dapm = w->dapm; struct hdac_hdmi_port *port = w->priv; struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_pcm *pcm = NULL; const char *cvt_name = e->texts[ucontrol->value.enumerated.item[0]]; @@ -922,7 +923,7 @@ static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev, struct snd_soc_dapm_widget *widget, const char *widget_name) { - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_pin *pin = port->pin; struct snd_kcontrol_new *kc; struct hdac_hdmi_cvt *cvt; @@ -990,7 +991,7 @@ static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev, struct snd_soc_dapm_widget *widgets, struct snd_soc_dapm_route *route, int rindex) { - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); const struct snd_kcontrol_new *kc; struct soc_enum *se; int mux_index = hdmi->num_cvt + hdmi->num_ports; @@ -1033,7 +1034,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) struct snd_soc_dapm_widget *widgets; struct snd_soc_dapm_route *route; struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct snd_soc_dai_driver *dai_drv = dapm->component->dai_drv; char widget_name[NAME_SIZE]; struct hdac_hdmi_cvt *cvt; @@ -1134,7 +1135,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) { - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_cvt *cvt; int dai_id = 0; @@ -1161,7 +1162,7 @@ static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) { - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_cvt *cvt; char name[NAME_SIZE]; @@ -1209,7 +1210,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, struct hdac_hdmi_port *port) { struct hdac_ext_device *edev = pin->edev; - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_pcm *pcm; int size = 0; int port_id = -1; @@ -1304,7 +1305,7 @@ static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi, static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) { - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_pin *pin; int ret; @@ -1336,8 +1337,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac) { unsigned int vendor_param; - struct hdac_ext_device *edev = to_ehdac_device(hdac); - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); unsigned int vendor_nid = hdmi->drv_data->vendor_nid; vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0, @@ -1355,8 +1355,7 @@ static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac) static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac) { unsigned int vendor_param; - struct hdac_ext_device *edev = to_ehdac_device(hdac); - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); unsigned int vendor_nid = hdmi->drv_data->vendor_nid; vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0, @@ -1452,9 +1451,9 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev, hda_nid_t nid; int i, num_nodes; struct hdac_device *hdac = &edev->hdac; - struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_cvt *temp_cvt, *cvt_next; struct hdac_hdmi_pin *temp_pin, *pin_next; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); int ret; hdac_hdmi_skl_enable_all_pins(hdac); @@ -1537,7 +1536,7 @@ free_widgets: static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) { struct hdac_ext_device *edev = aptr; - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_pin *pin = NULL; struct hdac_hdmi_port *hport = NULL; struct snd_soc_codec *codec = edev->scodec; @@ -1614,7 +1613,7 @@ static int create_fill_jack_kcontrols(struct snd_soc_card *card, char *name; int i = 0, j; struct snd_soc_codec *codec = edev->scodec; - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); kc = devm_kcalloc(codec->dev, hdmi->num_ports, sizeof(*kc), GFP_KERNEL); @@ -1652,7 +1651,7 @@ int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec, struct snd_soc_dapm_context *dapm) { struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_pin *pin; struct snd_soc_dapm_widget *widgets; struct snd_soc_dapm_route *route; @@ -1728,7 +1727,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, { struct snd_soc_codec *codec = dai->codec; struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_pcm *pcm; struct snd_pcm *snd_pcm; int err; @@ -1791,7 +1790,7 @@ static void hdac_hdmi_present_sense_all_pins(struct hdac_ext_device *edev, static int hdmi_codec_probe(struct snd_soc_codec *codec) { struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(&codec->component); struct hdac_ext_link *hlink = NULL; @@ -1870,7 +1869,7 @@ static int hdmi_codec_prepare(struct device *dev) static void hdmi_codec_complete(struct device *dev) { struct hdac_ext_device *edev = to_hda_ext_device(dev); - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_device *hdac = &edev->hdac; /* Power up afg */ @@ -1904,8 +1903,7 @@ static const struct snd_soc_codec_driver hdmi_hda_codec = { static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx, unsigned char *chmap) { - struct hdac_ext_device *edev = to_ehdac_device(hdac); - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); memcpy(chmap, pcm->chmap, ARRAY_SIZE(pcm->chmap)); @@ -1915,7 +1913,7 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, unsigned char *chmap, int prepared) { struct hdac_ext_device *edev = to_ehdac_device(hdac); - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); struct hdac_hdmi_port *port; @@ -1936,8 +1934,7 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) { - struct hdac_ext_device *edev = to_ehdac_device(hdac); - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); if (!pcm) @@ -1951,8 +1948,7 @@ static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) { - struct hdac_ext_device *edev = to_ehdac_device(hdac); - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); struct hdac_hdmi_port *port; @@ -2058,7 +2054,7 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) { - struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_pin *pin, *pin_next; struct hdac_hdmi_cvt *cvt, *cvt_next; struct hdac_hdmi_pcm *pcm, *pcm_next; -- cgit v1.2.3 From 72bc39cf53fabf56907f9d6c4b120fc49d9abc95 Mon Sep 17 00:00:00 2001 From: "Ughreja, Rakesh A" Date: Fri, 1 Dec 2017 14:43:18 +0530 Subject: ASoC: hdac_hdmi: clean up hdac_ext_device variable names Existing code uses hdac and edev inconsistently to represent hdac_ext_device structure which creates confusion because hdac is used even to represent hdac_device. So this patch replaces all the variable instances of hdac_ext_device with edev. In the later patch all the variable instances of hdac_device will be replaced with hdev. This prepares the code base to remove the usage of hdac_ext_device data structures done in the subsequent patches. Signed-off-by: Rakesh Ughreja Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 82 ++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 05af2299579b..98a695ba9373 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -197,18 +197,18 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, /* * Get the no devices that can be connected to a port on the Pin widget. */ -static int hdac_hdmi_get_port_len(struct hdac_ext_device *hdac, hda_nid_t nid) +static int hdac_hdmi_get_port_len(struct hdac_ext_device *edev, hda_nid_t nid) { unsigned int caps; unsigned int type, param; - caps = get_wcaps(&hdac->hdac, nid); + caps = get_wcaps(&edev->hdac, nid); type = get_wcaps_type(caps); if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN)) return 0; - param = snd_hdac_read_parm_uncached(&hdac->hdac, nid, + param = snd_hdac_read_parm_uncached(&edev->hdac, nid, AC_PAR_DEVLIST_LEN); if (param == -1) return param; @@ -221,10 +221,10 @@ static int hdac_hdmi_get_port_len(struct hdac_ext_device *hdac, hda_nid_t nid) * id selected on the pin. Return 0 means the first port entry * is selected or MST is not supported. */ -static int hdac_hdmi_port_select_get(struct hdac_ext_device *hdac, +static int hdac_hdmi_port_select_get(struct hdac_ext_device *edev, struct hdac_hdmi_port *port) { - return snd_hdac_codec_read(&hdac->hdac, port->pin->nid, + return snd_hdac_codec_read(&edev->hdac, port->pin->nid, 0, AC_VERB_GET_DEVICE_SEL, 0); } @@ -232,7 +232,7 @@ static int hdac_hdmi_port_select_get(struct hdac_ext_device *hdac, * Sets the selected port entry for the configuring Pin widget verb. * returns error if port set is not equal to port get otherwise success */ -static int hdac_hdmi_port_select_set(struct hdac_ext_device *hdac, +static int hdac_hdmi_port_select_set(struct hdac_ext_device *edev, struct hdac_hdmi_port *port) { int num_ports; @@ -241,7 +241,7 @@ static int hdac_hdmi_port_select_set(struct hdac_ext_device *hdac, return 0; /* AC_PAR_DEVLIST_LEN is 0 based. */ - num_ports = hdac_hdmi_get_port_len(hdac, port->pin->nid); + num_ports = hdac_hdmi_get_port_len(edev, port->pin->nid); if (num_ports < 0) return -EIO; @@ -252,13 +252,13 @@ static int hdac_hdmi_port_select_set(struct hdac_ext_device *hdac, if (num_ports + 1 < port->id) return 0; - snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0, + snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0, AC_VERB_SET_DEVICE_SEL, port->id); - if (port->id != hdac_hdmi_port_select_get(hdac, port)) + if (port->id != hdac_hdmi_port_select_get(edev, port)) return -EIO; - dev_dbg(&hdac->hdac.dev, "Selected the port=%d\n", port->id); + dev_dbg(&edev->hdac.dev, "Selected the port=%d\n", port->id); return 0; } @@ -323,14 +323,14 @@ format_constraint: } static void -hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid, +hdac_hdmi_set_dip_index(struct hdac_ext_device *edev, hda_nid_t pin_nid, int packet_index, int byte_index) { int val; val = (packet_index << 5) | (byte_index & 0x1f); - snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + snd_hdac_codec_write(&edev->hdac, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); } @@ -346,14 +346,14 @@ struct dp_audio_infoframe { u8 LFEPBL01_LSV36_DM_INH7; }; -static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, +static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *edev, struct hdac_hdmi_pcm *pcm, struct hdac_hdmi_port *port) { uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; struct hdmi_audio_infoframe frame; struct hdac_hdmi_pin *pin = port->pin; struct dp_audio_infoframe dp_ai; - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&hdac->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_cvt *cvt = pcm->cvt; u8 *dip; int ret; @@ -362,11 +362,11 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, u8 conn_type; int channels, ca; - ca = snd_hdac_channel_allocation(&hdac->hdac, port->eld.info.spk_alloc, + ca = snd_hdac_channel_allocation(&edev->hdac, port->eld.info.spk_alloc, pcm->channels, pcm->chmap_set, true, pcm->chmap); channels = snd_hdac_get_active_channels(ca); - hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt->nid, channels); + hdmi->chmap.ops.set_channel_count(&edev->hdac, cvt->nid, channels); snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca, pcm->channels, pcm->chmap, pcm->chmap_set); @@ -399,32 +399,32 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, break; default: - dev_err(&hdac->hdac.dev, "Invalid connection type: %d\n", + dev_err(&edev->hdac.dev, "Invalid connection type: %d\n", conn_type); return -EIO; } /* stop infoframe transmission */ - hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0); - snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, + hdac_hdmi_set_dip_index(edev, pin->nid, 0x0, 0x0); + snd_hdac_codec_write(&edev->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE); /* Fill infoframe. Index auto-incremented */ - hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0); + hdac_hdmi_set_dip_index(edev, pin->nid, 0x0, 0x0); if (conn_type == DRM_ELD_CONN_TYPE_HDMI) { for (i = 0; i < sizeof(buffer); i++) - snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, + snd_hdac_codec_write(&edev->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_DATA, buffer[i]); } else { for (i = 0; i < sizeof(dp_ai); i++) - snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, + snd_hdac_codec_write(&edev->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_DATA, dip[i]); } /* Start infoframe */ - hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0); - snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, + hdac_hdmi_set_dip_index(edev, pin->nid, 0x0, 0x0); + snd_hdac_codec_write(&edev->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST); return 0; @@ -454,8 +454,8 @@ static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai, static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai) { - struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&hdac->hdac); + struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_port *port; struct hdac_hdmi_pcm *pcm; @@ -468,7 +468,7 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, return -ENODEV; if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) { - dev_err(&hdac->hdac.dev, + dev_err(&edev->hdac.dev, "device is not configured for this pin:port%d:%d\n", port->pin->nid, port->id); return -ENODEV; @@ -488,28 +488,28 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, return 0; } -static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *hdac, +static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *edev, struct hdac_hdmi_pin *pin, struct hdac_hdmi_port *port) { - if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { - dev_warn(&hdac->hdac.dev, + if (!(get_wcaps(&edev->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { + dev_warn(&edev->hdac.dev, "HDMI: pin %d wcaps %#x does not support connection list\n", - pin->nid, get_wcaps(&hdac->hdac, pin->nid)); + pin->nid, get_wcaps(&edev->hdac, pin->nid)); return -EINVAL; } - if (hdac_hdmi_port_select_set(hdac, port) < 0) + if (hdac_hdmi_port_select_set(edev, port) < 0) return -EIO; - port->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, + port->num_mux_nids = snd_hdac_get_connections(&edev->hdac, pin->nid, port->mux_nids, HDA_MAX_CONNECTIONS); if (port->num_mux_nids == 0) - dev_warn(&hdac->hdac.dev, + dev_warn(&edev->hdac.dev, "No connections found for pin:port %d:%d\n", pin->nid, port->id); - dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin:port %d:%d\n", + dev_dbg(&edev->hdac.dev, "num_mux_nids %d for pin:port %d:%d\n", port->num_mux_nids, pin->nid, port->id); return port->num_mux_nids; @@ -567,8 +567,8 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt( static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&hdac->hdac); + struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_cvt *cvt; struct hdac_hdmi_port *port; @@ -577,7 +577,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, dai_map = &hdmi->dai_map[dai->id]; cvt = dai_map->cvt; - port = hdac_hdmi_get_port_from_cvt(hdac, hdmi, cvt); + port = hdac_hdmi_get_port_from_cvt(edev, hdmi, cvt); /* * To make PA and other userland happy. @@ -588,7 +588,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) { - dev_warn(&hdac->hdac.dev, + dev_warn(&edev->hdac.dev, "Failed: present?:%d ELD valid?:%d pin:port: %d:%d\n", port->eld.monitor_present, port->eld.eld_valid, port->pin->nid, port->id); @@ -610,8 +610,8 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&hdac->hdac); + struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_pcm *pcm; -- cgit v1.2.3 From f0c5ebebacf3cc246e51e8814f5d4b22179f37bd Mon Sep 17 00:00:00 2001 From: "Ughreja, Rakesh A" Date: Fri, 1 Dec 2017 14:43:19 +0530 Subject: ASoC: hdac_hdmi: clean up hdac_device variable names This patch renames all the variable instances of hdac_device with hdev to prepare the code base to remove the usage of hdac_ext_device data structures done in the following patches. Existing code uses hdev and hdac as variable names for hdac_device as well as hdac_ext_device, which creates confusion. Signed-off-by: Rakesh Ughreja Signed-off-by: Mark Brown --- include/sound/hdaudio_ext.h | 4 +- sound/hda/ext/hdac_ext_bus.c | 2 +- sound/soc/codecs/hdac_hdmi.c | 312 +++++++++++++++++++++---------------------- 3 files changed, 159 insertions(+), 159 deletions(-) diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index ca00130cb028..9c14e21dda85 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h @@ -193,7 +193,7 @@ struct hda_dai_map { * @pvt_data - private data, for asoc contains asoc codec object */ struct hdac_ext_device { - struct hdac_device hdac; + struct hdac_device hdev; struct hdac_ext_bus *ebus; /* soc-dai to nid map */ @@ -213,7 +213,7 @@ struct hdac_ext_dma_params { u8 stream_tag; }; #define to_ehdac_device(dev) (container_of((dev), \ - struct hdac_ext_device, hdac)) + struct hdac_ext_device, hdev)) /* * HD-audio codec base driver */ diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index 31b510c5ca0b..0daf31383084 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c @@ -146,7 +146,7 @@ int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *ebus, int addr) edev = kzalloc(sizeof(*edev), GFP_KERNEL); if (!edev) return -ENOMEM; - hdev = &edev->hdac; + hdev = &edev->hdev; edev->ebus = ebus; snprintf(name, sizeof(name), "ehdaudio%dD%d", ebus->idx, addr); diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 98a695ba9373..3a35ede7027d 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -171,7 +171,7 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, * ports. */ if (pcm->jack_event == 0) { - dev_dbg(&edev->hdac.dev, + dev_dbg(&edev->hdev.dev, "jack report for pcm=%d\n", pcm->pcm_id); snd_soc_jack_report(pcm->jack, SND_JACK_AVOUT, @@ -202,13 +202,13 @@ static int hdac_hdmi_get_port_len(struct hdac_ext_device *edev, hda_nid_t nid) unsigned int caps; unsigned int type, param; - caps = get_wcaps(&edev->hdac, nid); + caps = get_wcaps(&edev->hdev, nid); type = get_wcaps_type(caps); if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN)) return 0; - param = snd_hdac_read_parm_uncached(&edev->hdac, nid, + param = snd_hdac_read_parm_uncached(&edev->hdev, nid, AC_PAR_DEVLIST_LEN); if (param == -1) return param; @@ -224,7 +224,7 @@ static int hdac_hdmi_get_port_len(struct hdac_ext_device *edev, hda_nid_t nid) static int hdac_hdmi_port_select_get(struct hdac_ext_device *edev, struct hdac_hdmi_port *port) { - return snd_hdac_codec_read(&edev->hdac, port->pin->nid, + return snd_hdac_codec_read(&edev->hdev, port->pin->nid, 0, AC_VERB_GET_DEVICE_SEL, 0); } @@ -252,13 +252,13 @@ static int hdac_hdmi_port_select_set(struct hdac_ext_device *edev, if (num_ports + 1 < port->id) return 0; - snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0, + snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0, AC_VERB_SET_DEVICE_SEL, port->id); if (port->id != hdac_hdmi_port_select_get(edev, port)) return -EIO; - dev_dbg(&edev->hdac.dev, "Selected the port=%d\n", port->id); + dev_dbg(&edev->hdev.dev, "Selected the port=%d\n", port->id); return 0; } @@ -278,9 +278,9 @@ static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) { - struct hdac_device *hdac = dev_to_hdac_dev(dev); + struct hdac_device *hdev = dev_to_hdac_dev(dev); - return to_ehdac_device(hdac); + return to_ehdac_device(hdev); } static unsigned int sad_format(const u8 *sad) @@ -330,7 +330,7 @@ hdac_hdmi_set_dip_index(struct hdac_ext_device *edev, hda_nid_t pin_nid, val = (packet_index << 5) | (byte_index & 0x1f); - snd_hdac_codec_write(&edev->hdac, pin_nid, 0, + snd_hdac_codec_write(&edev->hdev, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); } @@ -353,7 +353,7 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *edev, struct hdmi_audio_infoframe frame; struct hdac_hdmi_pin *pin = port->pin; struct dp_audio_infoframe dp_ai; - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_cvt *cvt = pcm->cvt; u8 *dip; int ret; @@ -362,11 +362,11 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *edev, u8 conn_type; int channels, ca; - ca = snd_hdac_channel_allocation(&edev->hdac, port->eld.info.spk_alloc, + ca = snd_hdac_channel_allocation(&edev->hdev, port->eld.info.spk_alloc, pcm->channels, pcm->chmap_set, true, pcm->chmap); channels = snd_hdac_get_active_channels(ca); - hdmi->chmap.ops.set_channel_count(&edev->hdac, cvt->nid, channels); + hdmi->chmap.ops.set_channel_count(&edev->hdev, cvt->nid, channels); snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca, pcm->channels, pcm->chmap, pcm->chmap_set); @@ -399,14 +399,14 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *edev, break; default: - dev_err(&edev->hdac.dev, "Invalid connection type: %d\n", + dev_err(&edev->hdev.dev, "Invalid connection type: %d\n", conn_type); return -EIO; } /* stop infoframe transmission */ hdac_hdmi_set_dip_index(edev, pin->nid, 0x0, 0x0); - snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + snd_hdac_codec_write(&edev->hdev, pin->nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE); @@ -414,17 +414,17 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *edev, hdac_hdmi_set_dip_index(edev, pin->nid, 0x0, 0x0); if (conn_type == DRM_ELD_CONN_TYPE_HDMI) { for (i = 0; i < sizeof(buffer); i++) - snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + snd_hdac_codec_write(&edev->hdev, pin->nid, 0, AC_VERB_SET_HDMI_DIP_DATA, buffer[i]); } else { for (i = 0; i < sizeof(dp_ai); i++) - snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + snd_hdac_codec_write(&edev->hdev, pin->nid, 0, AC_VERB_SET_HDMI_DIP_DATA, dip[i]); } /* Start infoframe */ hdac_hdmi_set_dip_index(edev, pin->nid, 0x0, 0x0); - snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + snd_hdac_codec_write(&edev->hdev, pin->nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST); return 0; @@ -435,11 +435,11 @@ static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai, int slots, int slot_width) { struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_pcm *pcm; - dev_dbg(&edev->hdac.dev, "%s: strm_tag: %d\n", __func__, tx_mask); + dev_dbg(&edev->hdev.dev, "%s: strm_tag: %d\n", __func__, tx_mask); dai_map = &hdmi->dai_map[dai->id]; @@ -455,7 +455,7 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai) { struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_port *port; struct hdac_hdmi_pcm *pcm; @@ -468,7 +468,7 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, return -ENODEV; if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) { - dev_err(&edev->hdac.dev, + dev_err(&edev->hdev.dev, "device is not configured for this pin:port%d:%d\n", port->pin->nid, port->id); return -ENODEV; @@ -492,24 +492,24 @@ static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *edev, struct hdac_hdmi_pin *pin, struct hdac_hdmi_port *port) { - if (!(get_wcaps(&edev->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { - dev_warn(&edev->hdac.dev, + if (!(get_wcaps(&edev->hdev, pin->nid) & AC_WCAP_CONN_LIST)) { + dev_warn(&edev->hdev.dev, "HDMI: pin %d wcaps %#x does not support connection list\n", - pin->nid, get_wcaps(&edev->hdac, pin->nid)); + pin->nid, get_wcaps(&edev->hdev, pin->nid)); return -EINVAL; } if (hdac_hdmi_port_select_set(edev, port) < 0) return -EIO; - port->num_mux_nids = snd_hdac_get_connections(&edev->hdac, pin->nid, + port->num_mux_nids = snd_hdac_get_connections(&edev->hdev, pin->nid, port->mux_nids, HDA_MAX_CONNECTIONS); if (port->num_mux_nids == 0) - dev_warn(&edev->hdac.dev, + dev_warn(&edev->hdev.dev, "No connections found for pin:port %d:%d\n", pin->nid, port->id); - dev_dbg(&edev->hdac.dev, "num_mux_nids %d for pin:port %d:%d\n", + dev_dbg(&edev->hdev.dev, "num_mux_nids %d for pin:port %d:%d\n", port->num_mux_nids, pin->nid, port->id); return port->num_mux_nids; @@ -568,7 +568,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_cvt *cvt; struct hdac_hdmi_port *port; @@ -588,7 +588,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) { - dev_warn(&edev->hdac.dev, + dev_warn(&edev->hdev.dev, "Failed: present?:%d ELD valid?:%d pin:port: %d:%d\n", port->eld.monitor_present, port->eld.eld_valid, port->pin->nid, port->id); @@ -611,7 +611,7 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_pcm *pcm; @@ -632,13 +632,13 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, } static int -hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) +hdac_hdmi_query_cvt_params(struct hdac_device *hdev, struct hdac_hdmi_cvt *cvt) { unsigned int chans; - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); int err; - chans = get_wcaps(hdac, cvt->nid); + chans = get_wcaps(hdev, cvt->nid); chans = get_wcaps_channels(chans); cvt->params.channels_min = 2; @@ -647,12 +647,12 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) if (chans > hdmi->chmap.channels_max) hdmi->chmap.channels_max = chans; - err = snd_hdac_query_supported_pcm(hdac, cvt->nid, + err = snd_hdac_query_supported_pcm(hdev, cvt->nid, &cvt->params.rates, &cvt->params.formats, &cvt->params.maxbps); if (err < 0) - dev_err(&hdac->dev, + dev_err(&hdev->dev, "Failed to query pcm params for nid %d: %d\n", cvt->nid, err); @@ -697,7 +697,7 @@ static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, struct hdac_hdmi_port *port) { - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_pcm *pcm = NULL; struct hdac_hdmi_port *p; @@ -717,9 +717,9 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, hda_nid_t nid, unsigned int pwr_state) { - if (get_wcaps(&edev->hdac, nid) & AC_WCAP_POWER) { - if (!snd_hdac_check_power_state(&edev->hdac, nid, pwr_state)) - snd_hdac_codec_write(&edev->hdac, nid, 0, + if (get_wcaps(&edev->hdev, nid) & AC_WCAP_POWER) { + if (!snd_hdac_check_power_state(&edev->hdev, nid, pwr_state)) + snd_hdac_codec_write(&edev->hdev, nid, 0, AC_VERB_SET_POWER_STATE, pwr_state); } } @@ -727,8 +727,8 @@ static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, static void hdac_hdmi_set_amp(struct hdac_ext_device *edev, hda_nid_t nid, int val) { - if (get_wcaps(&edev->hdac, nid) & AC_WCAP_OUT_AMP) - snd_hdac_codec_write(&edev->hdac, nid, 0, + if (get_wcaps(&edev->hdev, nid) & AC_WCAP_OUT_AMP) + snd_hdac_codec_write(&edev->hdev, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); } @@ -740,7 +740,7 @@ static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w, struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); struct hdac_hdmi_pcm *pcm; - dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", + dev_dbg(&edev->hdev.dev, "%s: widget: %s event: %x\n", __func__, w->name, event); pcm = hdac_hdmi_get_pcm(edev, port); @@ -756,7 +756,7 @@ static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w, hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D0); /* Enable out path for this pin widget */ - snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0, + snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); hdac_hdmi_set_amp(edev, port->pin->nid, AMP_OUT_UNMUTE); @@ -767,7 +767,7 @@ static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w, hdac_hdmi_set_amp(edev, port->pin->nid, AMP_OUT_MUTE); /* Disable out path for this pin widget */ - snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0, + snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0); hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D3); @@ -783,10 +783,10 @@ static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w, { struct hdac_hdmi_cvt *cvt = w->priv; struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_pcm *pcm; - dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", + dev_dbg(&edev->hdev.dev, "%s: widget: %s event: %x\n", __func__, w->name, event); pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, cvt); @@ -798,23 +798,23 @@ static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w, hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D0); /* Enable transmission */ - snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + snd_hdac_codec_write(&edev->hdev, cvt->nid, 0, AC_VERB_SET_DIGI_CONVERT_1, 1); /* Category Code (CC) to zero */ - snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + snd_hdac_codec_write(&edev->hdev, cvt->nid, 0, AC_VERB_SET_DIGI_CONVERT_2, 0); - snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + snd_hdac_codec_write(&edev->hdev, cvt->nid, 0, AC_VERB_SET_CHANNEL_STREAMID, pcm->stream_tag); - snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + snd_hdac_codec_write(&edev->hdev, cvt->nid, 0, AC_VERB_SET_STREAM_FORMAT, pcm->format); break; case SND_SOC_DAPM_POST_PMD: - snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + snd_hdac_codec_write(&edev->hdev, cvt->nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); - snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + snd_hdac_codec_write(&edev->hdev, cvt->nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D3); @@ -832,7 +832,7 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w, struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); int mux_idx; - dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", + dev_dbg(&edev->hdev.dev, "%s: widget: %s event: %x\n", __func__, w->name, event); if (!kc) @@ -845,7 +845,7 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w, return -EIO; if (mux_idx > 0) { - snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0, + snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0, AC_VERB_SET_CONNECT_SEL, (mux_idx - 1)); } @@ -865,7 +865,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_context *dapm = w->dapm; struct hdac_hdmi_port *port = w->priv; struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_pcm *pcm = NULL; const char *cvt_name = e->texts[ucontrol->value.enumerated.item[0]]; @@ -923,7 +923,7 @@ static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev, struct snd_soc_dapm_widget *widget, const char *widget_name) { - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_pin *pin = port->pin; struct snd_kcontrol_new *kc; struct hdac_hdmi_cvt *cvt; @@ -935,17 +935,17 @@ static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev, int i = 0; int num_items = hdmi->num_cvt + 1; - kc = devm_kzalloc(&edev->hdac.dev, sizeof(*kc), GFP_KERNEL); + kc = devm_kzalloc(&edev->hdev.dev, sizeof(*kc), GFP_KERNEL); if (!kc) return -ENOMEM; - se = devm_kzalloc(&edev->hdac.dev, sizeof(*se), GFP_KERNEL); + se = devm_kzalloc(&edev->hdev.dev, sizeof(*se), GFP_KERNEL); if (!se) return -ENOMEM; snprintf(kc_name, NAME_SIZE, "Pin %d port %d Input", pin->nid, port->id); - kc->name = devm_kstrdup(&edev->hdac.dev, kc_name, GFP_KERNEL); + kc->name = devm_kstrdup(&edev->hdev.dev, kc_name, GFP_KERNEL); if (!kc->name) return -ENOMEM; @@ -963,24 +963,24 @@ static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev, se->mask = roundup_pow_of_two(se->items) - 1; sprintf(mux_items, "NONE"); - items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL); + items[i] = devm_kstrdup(&edev->hdev.dev, mux_items, GFP_KERNEL); if (!items[i]) return -ENOMEM; list_for_each_entry(cvt, &hdmi->cvt_list, head) { i++; sprintf(mux_items, "cvt %d", cvt->nid); - items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL); + items[i] = devm_kstrdup(&edev->hdev.dev, mux_items, GFP_KERNEL); if (!items[i]) return -ENOMEM; } - se->texts = devm_kmemdup(&edev->hdac.dev, items, + se->texts = devm_kmemdup(&edev->hdev.dev, items, (num_items * sizeof(char *)), GFP_KERNEL); if (!se->texts) return -ENOMEM; - return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget, + return hdac_hdmi_fill_widget_info(&edev->hdev.dev, widget, snd_soc_dapm_mux, port, widget_name, NULL, kc, 1, hdac_hdmi_pin_mux_widget_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_REG); @@ -991,7 +991,7 @@ static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev, struct snd_soc_dapm_widget *widgets, struct snd_soc_dapm_route *route, int rindex) { - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); const struct snd_kcontrol_new *kc; struct soc_enum *se; int mux_index = hdmi->num_cvt + hdmi->num_ports; @@ -1034,7 +1034,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) struct snd_soc_dapm_widget *widgets; struct snd_soc_dapm_route *route; struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct snd_soc_dai_driver *dai_drv = dapm->component->dai_drv; char widget_name[NAME_SIZE]; struct hdac_hdmi_cvt *cvt; @@ -1135,7 +1135,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) { - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_cvt *cvt; int dai_id = 0; @@ -1151,7 +1151,7 @@ static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) dai_id++; if (dai_id == HDA_MAX_CVTS) { - dev_warn(&edev->hdac.dev, + dev_warn(&edev->hdev.dev, "Max dais supported: %d\n", dai_id); break; } @@ -1162,7 +1162,7 @@ static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) { - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_cvt *cvt; char name[NAME_SIZE]; @@ -1177,7 +1177,7 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) list_add_tail(&cvt->head, &hdmi->cvt_list); hdmi->num_cvt++; - return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); + return hdac_hdmi_query_cvt_params(&edev->hdev, cvt); } static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, @@ -1189,7 +1189,7 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, >> DRM_ELD_VER_SHIFT; if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) { - dev_err(&edev->hdac.dev, "HDMI: Unknown ELD version %d\n", ver); + dev_err(&edev->hdev.dev, "HDMI: Unknown ELD version %d\n", ver); return -EINVAL; } @@ -1197,7 +1197,7 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; if (mnl > ELD_MAX_MNL) { - dev_err(&edev->hdac.dev, "HDMI: MNL Invalid %d\n", mnl); + dev_err(&edev->hdev.dev, "HDMI: MNL Invalid %d\n", mnl); return -EINVAL; } @@ -1210,7 +1210,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, struct hdac_hdmi_port *port) { struct hdac_ext_device *edev = pin->edev; - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_pcm *pcm; int size = 0; int port_id = -1; @@ -1228,7 +1228,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, if (pin->mst_capable) port_id = port->id; - size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, port_id, + size = snd_hdac_acomp_get_eld(&edev->hdev, pin->nid, port_id, &port->eld.monitor_present, port->eld.eld_buffer, ELD_MAX_SIZE); @@ -1251,7 +1251,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, if (!port->eld.monitor_present || !port->eld.eld_valid) { - dev_err(&edev->hdac.dev, "%s: disconnect for pin:port %d:%d\n", + dev_err(&edev->hdev.dev, "%s: disconnect for pin:port %d:%d\n", __func__, pin->nid, port->id); /* @@ -1305,7 +1305,7 @@ static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi, static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) { - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_pin *pin; int ret; @@ -1334,38 +1334,38 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) #define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ #define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ -static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac) +static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdev) { unsigned int vendor_param; - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); unsigned int vendor_nid = hdmi->drv_data->vendor_nid; - vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0, + vendor_param = snd_hdac_codec_read(hdev, vendor_nid, 0, INTEL_GET_VENDOR_VERB, 0); if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS) return; vendor_param |= INTEL_EN_ALL_PIN_CVTS; - vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0, + vendor_param = snd_hdac_codec_read(hdev, vendor_nid, 0, INTEL_SET_VENDOR_VERB, vendor_param); if (vendor_param == -1) return; } -static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac) +static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdev) { unsigned int vendor_param; - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); unsigned int vendor_nid = hdmi->drv_data->vendor_nid; - vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0, + vendor_param = snd_hdac_codec_read(hdev, vendor_nid, 0, INTEL_GET_VENDOR_VERB, 0); if (vendor_param == -1 || vendor_param & INTEL_EN_DP12) return; /* enable DP1.2 mode */ vendor_param |= INTEL_EN_DP12; - vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0, + vendor_param = snd_hdac_codec_read(hdev, vendor_nid, 0, INTEL_SET_VENDOR_VERB, vendor_param); if (vendor_param == -1) return; @@ -1383,7 +1383,7 @@ static const struct snd_soc_dai_ops hdmi_dai_ops = { * Each converter can support a stream independently. So a dai is created * based on the number of converter queried. */ -static int hdac_hdmi_create_dais(struct hdac_device *hdac, +static int hdac_hdmi_create_dais(struct hdac_device *hdev, struct snd_soc_dai_driver **dais, struct hdac_hdmi_priv *hdmi, int num_dais) { @@ -1396,20 +1396,20 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdac, u64 formats; int ret; - hdmi_dais = devm_kzalloc(&hdac->dev, + hdmi_dais = devm_kzalloc(&hdev->dev, (sizeof(*hdmi_dais) * num_dais), GFP_KERNEL); if (!hdmi_dais) return -ENOMEM; list_for_each_entry(cvt, &hdmi->cvt_list, head) { - ret = snd_hdac_query_supported_pcm(hdac, cvt->nid, + ret = snd_hdac_query_supported_pcm(hdev, cvt->nid, &rates, &formats, &bps); if (ret) return ret; sprintf(dai_name, "intel-hdmi-hifi%d", i+1); - hdmi_dais[i].name = devm_kstrdup(&hdac->dev, + hdmi_dais[i].name = devm_kstrdup(&hdev->dev, dai_name, GFP_KERNEL); if (!hdmi_dais[i].name) @@ -1417,7 +1417,7 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdac, snprintf(name, sizeof(name), "hifi%d", i+1); hdmi_dais[i].playback.stream_name = - devm_kstrdup(&hdac->dev, name, GFP_KERNEL); + devm_kstrdup(&hdev->dev, name, GFP_KERNEL); if (!hdmi_dais[i].playback.stream_name) return -ENOMEM; @@ -1450,29 +1450,29 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev, { hda_nid_t nid; int i, num_nodes; - struct hdac_device *hdac = &edev->hdac; struct hdac_hdmi_cvt *temp_cvt, *cvt_next; struct hdac_hdmi_pin *temp_pin, *pin_next; - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); + struct hdac_device *hdev = &edev->hdev; int ret; - hdac_hdmi_skl_enable_all_pins(hdac); - hdac_hdmi_skl_enable_dp12(hdac); + hdac_hdmi_skl_enable_all_pins(hdev); + hdac_hdmi_skl_enable_dp12(hdev); - num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); + num_nodes = snd_hdac_get_sub_nodes(hdev, hdev->afg, &nid); if (!nid || num_nodes <= 0) { - dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n"); + dev_warn(&hdev->dev, "HDMI: failed to get afg sub nodes\n"); return -EINVAL; } - hdac->num_nodes = num_nodes; - hdac->start_nid = nid; + hdev->num_nodes = num_nodes; + hdev->start_nid = nid; - for (i = 0; i < hdac->num_nodes; i++, nid++) { + for (i = 0; i < hdev->num_nodes; i++, nid++) { unsigned int caps; unsigned int type; - caps = get_wcaps(hdac, nid); + caps = get_wcaps(hdev, nid); type = get_wcaps_type(caps); if (!(caps & AC_WCAP_DIGITAL)) @@ -1494,16 +1494,16 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev, } } - hdac->end_nid = nid; + hdev->end_nid = nid; if (!hdmi->num_pin || !hdmi->num_cvt) { ret = -EIO; goto free_widgets; } - ret = hdac_hdmi_create_dais(hdac, dais, hdmi, hdmi->num_cvt); + ret = hdac_hdmi_create_dais(hdev, dais, hdmi, hdmi->num_cvt); if (ret) { - dev_err(&hdac->dev, "Failed to create dais with err: %d\n", + dev_err(&hdev->dev, "Failed to create dais with err: %d\n", ret); goto free_widgets; } @@ -1536,7 +1536,7 @@ free_widgets: static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) { struct hdac_ext_device *edev = aptr; - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_pin *pin = NULL; struct hdac_hdmi_port *hport = NULL; struct snd_soc_codec *codec = edev->scodec; @@ -1545,7 +1545,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) /* Don't know how this mapping is derived */ hda_nid_t pin_nid = port + 0x04; - dev_dbg(&edev->hdac.dev, "%s: for pin:%d port=%d\n", __func__, + dev_dbg(&edev->hdev.dev, "%s: for pin:%d port=%d\n", __func__, pin_nid, pipe); /* @@ -1558,7 +1558,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) SNDRV_CTL_POWER_D0) return; - if (atomic_read(&edev->hdac.in_pm)) + if (atomic_read(&edev->hdev.in_pm)) return; list_for_each_entry(pin, &hdmi->pin_list, head) { @@ -1613,7 +1613,7 @@ static int create_fill_jack_kcontrols(struct snd_soc_card *card, char *name; int i = 0, j; struct snd_soc_codec *codec = edev->scodec; - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); kc = devm_kcalloc(codec->dev, hdmi->num_ports, sizeof(*kc), GFP_KERNEL); @@ -1651,7 +1651,7 @@ int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec, struct snd_soc_dapm_context *dapm) { struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_pin *pin; struct snd_soc_dapm_widget *widgets; struct snd_soc_dapm_route *route; @@ -1727,7 +1727,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, { struct snd_soc_codec *codec = dai->codec; struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_pcm *pcm; struct snd_pcm *snd_pcm; int err; @@ -1749,7 +1749,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, if (snd_pcm) { err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap); if (err < 0) { - dev_err(&edev->hdac.dev, + dev_err(&edev->hdev.dev, "chmap control add failed with err: %d for pcm: %d\n", err, device); kfree(pcm); @@ -1790,7 +1790,7 @@ static void hdac_hdmi_present_sense_all_pins(struct hdac_ext_device *edev, static int hdmi_codec_probe(struct snd_soc_codec *codec) { struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(&codec->component); struct hdac_ext_link *hlink = NULL; @@ -1802,9 +1802,9 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) * hold the ref while we probe, also no need to drop the ref on * exit, we call pm_runtime_suspend() so that will do for us */ - hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); + hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdev.dev)); if (!hlink) { - dev_err(&edev->hdac.dev, "hdac link not found\n"); + dev_err(&edev->hdev.dev, "hdac link not found\n"); return -EIO; } @@ -1817,7 +1817,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) aops.audio_ptr = edev; ret = snd_hdac_i915_register_notifier(&aops); if (ret < 0) { - dev_err(&edev->hdac.dev, "notifier register failed: err: %d\n", + dev_err(&edev->hdev.dev, "notifier register failed: err: %d\n", ret); return ret; } @@ -1830,9 +1830,9 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) * hdac_device core already sets the state to active and calls * get_noresume. So enable runtime and set the device to suspend. */ - pm_runtime_enable(&edev->hdac.dev); - pm_runtime_put(&edev->hdac.dev); - pm_runtime_suspend(&edev->hdac.dev); + pm_runtime_enable(&edev->hdev.dev); + pm_runtime_put(&edev->hdev.dev); + pm_runtime_suspend(&edev->hdev.dev); return 0; } @@ -1841,7 +1841,7 @@ static int hdmi_codec_remove(struct snd_soc_codec *codec) { struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); - pm_runtime_disable(&edev->hdac.dev); + pm_runtime_disable(&edev->hdev.dev); return 0; } @@ -1849,9 +1849,9 @@ static int hdmi_codec_remove(struct snd_soc_codec *codec) static int hdmi_codec_prepare(struct device *dev) { struct hdac_ext_device *edev = to_hda_ext_device(dev); - struct hdac_device *hdac = &edev->hdac; + struct hdac_device *hdev = &edev->hdev; - pm_runtime_get_sync(&edev->hdac.dev); + pm_runtime_get_sync(&edev->hdev.dev); /* * Power down afg. @@ -1860,7 +1860,7 @@ static int hdmi_codec_prepare(struct device *dev) * is received. So setting power state is ensured without using loop * to read the state. */ - snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, + snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); return 0; @@ -1869,15 +1869,15 @@ static int hdmi_codec_prepare(struct device *dev) static void hdmi_codec_complete(struct device *dev) { struct hdac_ext_device *edev = to_hda_ext_device(dev); - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); - struct hdac_device *hdac = &edev->hdac; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); + struct hdac_device *hdev = &edev->hdev; /* Power up afg */ - snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, + snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - hdac_hdmi_skl_enable_all_pins(&edev->hdac); - hdac_hdmi_skl_enable_dp12(&edev->hdac); + hdac_hdmi_skl_enable_all_pins(&edev->hdev); + hdac_hdmi_skl_enable_dp12(&edev->hdev); /* * As the ELD notify callback request is not entertained while the @@ -1887,7 +1887,7 @@ static void hdmi_codec_complete(struct device *dev) */ hdac_hdmi_present_sense_all_pins(edev, hdmi, false); - pm_runtime_put_sync(&edev->hdac.dev); + pm_runtime_put_sync(&edev->hdev.dev); } #else #define hdmi_codec_prepare NULL @@ -1900,20 +1900,20 @@ static const struct snd_soc_codec_driver hdmi_hda_codec = { .idle_bias_off = true, }; -static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx, +static void hdac_hdmi_get_chmap(struct hdac_device *hdev, int pcm_idx, unsigned char *chmap) { - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); memcpy(chmap, pcm->chmap, ARRAY_SIZE(pcm->chmap)); } -static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, +static void hdac_hdmi_set_chmap(struct hdac_device *hdev, int pcm_idx, unsigned char *chmap, int prepared) { - struct hdac_ext_device *edev = to_ehdac_device(hdac); - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); + struct hdac_ext_device *edev = to_ehdac_device(hdev); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); struct hdac_hdmi_port *port; @@ -1932,9 +1932,9 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, mutex_unlock(&pcm->lock); } -static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) +static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdev, int pcm_idx) { - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); if (!pcm) @@ -1946,9 +1946,9 @@ static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) return true; } -static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) +static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx) { - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); struct hdac_hdmi_port *port; @@ -1979,30 +1979,30 @@ static struct hdac_hdmi_drv_data intel_drv_data = { static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) { - struct hdac_device *codec = &edev->hdac; + struct hdac_device *hdev = &edev->hdev; struct hdac_hdmi_priv *hdmi_priv; struct snd_soc_dai_driver *hdmi_dais = NULL; struct hdac_ext_link *hlink = NULL; int num_dais = 0; int ret = 0; - struct hdac_driver *hdrv = drv_to_hdac_driver(codec->dev.driver); - const struct hda_device_id *hdac_id = hdac_get_device_id(codec, hdrv); + struct hdac_driver *hdrv = drv_to_hdac_driver(hdev->dev.driver); + const struct hda_device_id *hdac_id = hdac_get_device_id(hdev, hdrv); /* hold the ref while we probe */ - hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); + hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdev.dev)); if (!hlink) { - dev_err(&edev->hdac.dev, "hdac link not found\n"); + dev_err(&edev->hdev.dev, "hdac link not found\n"); return -EIO; } snd_hdac_ext_bus_link_get(edev->ebus, hlink); - hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); + hdmi_priv = devm_kzalloc(&hdev->dev, sizeof(*hdmi_priv), GFP_KERNEL); if (hdmi_priv == NULL) return -ENOMEM; edev->private_data = hdmi_priv; - snd_hdac_register_chmap_ops(codec, &hdmi_priv->chmap); + snd_hdac_register_chmap_ops(hdev, &hdmi_priv->chmap); hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap; hdmi_priv->chmap.ops.set_chmap = hdac_hdmi_set_chmap; hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached; @@ -2017,7 +2017,7 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) else hdmi_priv->drv_data = &intel_drv_data; - dev_set_drvdata(&codec->dev, edev); + dev_set_drvdata(&hdev->dev, edev); INIT_LIST_HEAD(&hdmi_priv->pin_list); INIT_LIST_HEAD(&hdmi_priv->cvt_list); @@ -2028,9 +2028,9 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) * Turned off in the runtime_suspend during the first explicit * pm_runtime_suspend call. */ - ret = snd_hdac_display_power(edev->hdac.bus, true); + ret = snd_hdac_display_power(edev->hdev.bus, true); if (ret < 0) { - dev_err(&edev->hdac.dev, + dev_err(&edev->hdev.dev, "Cannot turn on display power on i915 err: %d\n", ret); return ret; @@ -2038,13 +2038,13 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) ret = hdac_hdmi_parse_and_map_nid(edev, &hdmi_dais, &num_dais); if (ret < 0) { - dev_err(&codec->dev, + dev_err(&hdev->dev, "Failed in parse and map nid with err: %d\n", ret); return ret; } /* ASoC specific initialization */ - ret = snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, + ret = snd_soc_register_codec(&hdev->dev, &hdmi_hda_codec, hdmi_dais, num_dais); snd_hdac_ext_bus_link_put(edev->ebus, hlink); @@ -2054,14 +2054,14 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) { - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdac); + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); struct hdac_hdmi_pin *pin, *pin_next; struct hdac_hdmi_cvt *cvt, *cvt_next; struct hdac_hdmi_pcm *pcm, *pcm_next; struct hdac_hdmi_port *port, *port_next; int i; - snd_soc_unregister_codec(&edev->hdac.dev); + snd_soc_unregister_codec(&edev->hdev.dev); list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { pcm->cvt = NULL; @@ -2097,8 +2097,8 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) static int hdac_hdmi_runtime_suspend(struct device *dev) { struct hdac_ext_device *edev = to_hda_ext_device(dev); - struct hdac_device *hdac = &edev->hdac; - struct hdac_bus *bus = hdac->bus; + struct hdac_device *hdev = &edev->hdev; + struct hdac_bus *bus = hdev->bus; struct hdac_ext_bus *ebus = hbus_to_ebus(bus); struct hdac_ext_link *hlink = NULL; int err; @@ -2116,7 +2116,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) * is received. So setting power state is ensured without using loop * to read the state. */ - snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, + snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); err = snd_hdac_display_power(bus, false); if (err < 0) { @@ -2138,8 +2138,8 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) static int hdac_hdmi_runtime_resume(struct device *dev) { struct hdac_ext_device *edev = to_hda_ext_device(dev); - struct hdac_device *hdac = &edev->hdac; - struct hdac_bus *bus = hdac->bus; + struct hdac_device *hdev = &edev->hdev; + struct hdac_bus *bus = hdev->bus; struct hdac_ext_bus *ebus = hbus_to_ebus(bus); struct hdac_ext_link *hlink = NULL; int err; @@ -2164,11 +2164,11 @@ static int hdac_hdmi_runtime_resume(struct device *dev) return err; } - hdac_hdmi_skl_enable_all_pins(&edev->hdac); - hdac_hdmi_skl_enable_dp12(&edev->hdac); + hdac_hdmi_skl_enable_all_pins(&edev->hdev); + hdac_hdmi_skl_enable_dp12(&edev->hdev); /* Power up afg */ - snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, + snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0); return 0; -- cgit v1.2.3 From 56ae83f11db58a3a62d0d309efb84544f2c02e3b Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Nov 2017 18:56:16 +0100 Subject: ASoC: tfa9879: Export OF device ID as module alias The I2C core always reports a MODALIAS of the form i2c: even if the device was registered via OF, this means that exporting the OF device ID table device aliases in the module is not needed. But in order to change how the core reports modaliases to user-space, it's better to export it. Before this patch: $ modinfo sound/soc/codecs/snd-soc-tfa9879.ko | grep alias alias: i2c:tfa9879 After this patch: $ modinfo sound/soc/codecs/snd-soc-tfa9879.ko | grep alias alias: i2c:tfa9879 alias: of:N*T*Cnxp,tfa9879C* alias: of:N*T*Cnxp,tfa9879 Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- sound/soc/codecs/tfa9879.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c index f8dd67ca0744..e7ca764b5729 100644 --- a/sound/soc/codecs/tfa9879.c +++ b/sound/soc/codecs/tfa9879.c @@ -316,6 +316,7 @@ static const struct of_device_id tfa9879_of_match[] = { { .compatible = "nxp,tfa9879", }, { } }; +MODULE_DEVICE_TABLE(of, tfa9879_of_match); static struct i2c_driver tfa9879_i2c_driver = { .driver = { -- cgit v1.2.3 From 8d6fb0bce2021baf056344cb0abb2df00c5fe6d5 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 29 Nov 2017 21:47:10 +0530 Subject: ASoC: ep93xx-ac97: Fix platform_get_irq's error checking The platform_get_irq() function returns negative if an error occurs. zero or positive number on success. platform_get_irq() error checking for zero is not correct. Signed-off-by: Arvind Yadav Signed-off-by: Mark Brown --- sound/soc/cirrus/ep93xx-ac97.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c index bbf7a9266a99..cd5a939ad608 100644 --- a/sound/soc/cirrus/ep93xx-ac97.c +++ b/sound/soc/cirrus/ep93xx-ac97.c @@ -365,7 +365,7 @@ static int ep93xx_ac97_probe(struct platform_device *pdev) { struct ep93xx_ac97_info *info; struct resource *res; - unsigned int irq; + int irq; int ret; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); @@ -378,8 +378,8 @@ static int ep93xx_ac97_probe(struct platform_device *pdev) return PTR_ERR(info->regs); irq = platform_get_irq(pdev, 0); - if (!irq) - return -ENODEV; + if (irq <= 0) + return irq < 0 ? irq : -ENODEV; ret = devm_request_irq(&pdev->dev, irq, ep93xx_ac97_interrupt, IRQF_TRIGGER_HIGH, pdev->name, info); -- cgit v1.2.3 From d6e2c4ffdf67de68e0263630525d2b521132d66a Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 29 Nov 2017 21:47:11 +0530 Subject: ASoC: mt8173: Fix platform_get_irq's error checking The platform_get_irq() function returns negative if an error occurs. zero or positive number on success. platform_get_irq() error checking for zero is not correct. Signed-off-by: Arvind Yadav Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-afe-pcm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c index 8a643a35d3d4..c7f7f8add5d9 100644 --- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c +++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c @@ -1083,7 +1083,7 @@ static int mt8173_afe_init_audio_clk(struct mtk_base_afe *afe) static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) { int ret, i; - unsigned int irq_id; + int irq_id; struct mtk_base_afe *afe; struct mt8173_afe_private *afe_priv; struct resource *res; @@ -1105,9 +1105,9 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) afe->dev = &pdev->dev; irq_id = platform_get_irq(pdev, 0); - if (!irq_id) { + if (irq_id <= 0) { dev_err(afe->dev, "np %s no irq\n", afe->dev->of_node->name); - return -ENXIO; + return irq_id < 0 ? irq_id : -ENXIO; } ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler, 0, "Afe_ISR_Handle", (void *)afe); -- cgit v1.2.3 From fa8cc38165c2f6f73bf947087b3cdc5dd9b9b560 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 29 Nov 2017 21:47:12 +0530 Subject: ASoC: nuc900: Fix platform_get_irq's error checking The platform_get_irq() function returns negative if an error occurs. zero or positive number on success. platform_get_irq() error checking for zero is not correct. Signed-off-by: Arvind Yadav Signed-off-by: Mark Brown --- sound/soc/nuc900/nuc900-ac97.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index b6615affe571..5e4fbd2d3479 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c @@ -346,8 +346,8 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev) } nuc900_audio->irq_num = platform_get_irq(pdev, 0); - if (!nuc900_audio->irq_num) { - ret = -EBUSY; + if (nuc900_audio->irq_num <= 0) { + ret = nuc900_audio->irq_num < 0 ? nuc900_audio->irq_num : -EBUSY; goto out; } -- cgit v1.2.3 From eee44bfcf931428d7e94a9ae2092d687386a135a Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 29 Nov 2017 21:47:13 +0530 Subject: ASoC: intel: sst: Handle return value of platform_get_irq platform_get_irq() can fail here and we must check its return value. Signed-off-by: Arvind Yadav Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 32d6e02e2104..6cd481bec275 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -236,6 +236,9 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) /* Find the IRQ */ ctx->irq_num = platform_get_irq(pdev, ctx->pdata->res_info->acpi_ipc_irq_index); + if (ctx->irq_num <= 0) + return ctx->irq_num < 0 ? ctx->irq_num : -EIO; + return 0; } -- cgit v1.2.3 From 00a5cc096774fbc9ac979765fa820e7c8d9121c4 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 29 Nov 2017 21:47:14 +0530 Subject: ASoC: intel: mfld: Handle return value of platform_get_irq platform_get_irq() can fail here and we must check its return value. Signed-off-by: Arvind Yadav Signed-off-by: Mark Brown --- sound/soc/intel/boards/mfld_machine.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/intel/boards/mfld_machine.c b/sound/soc/intel/boards/mfld_machine.c index 6f44acfb4aae..7cb44fdde1ee 100644 --- a/sound/soc/intel/boards/mfld_machine.c +++ b/sound/soc/intel/boards/mfld_machine.c @@ -372,6 +372,8 @@ static int snd_mfld_mc_probe(struct platform_device *pdev) /* retrive the irq number */ irq = platform_get_irq(pdev, 0); + if (irq <= 0) + return irq < 0 ? irq : -ENODEV; /* audio interrupt base of SRAM location where * interrupts are stored by System FW */ -- cgit v1.2.3 From ca7840fb47208a3521f3b60c1b78a2f0c59b4dc5 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 15:32:45 -0600 Subject: ASoC: tlv320aic31xx: General source formatting cleanup Simple non-functional changes including: * Fix spelling errors * Reformat code for easier reading * Remove unneeded code * Remove assignments that are always overridden * Normalize function return paths Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 63 ++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index d974e8651e30..07c014501e5e 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -136,8 +136,7 @@ static const struct regmap_config aic31xx_i2c_regmap = { .max_register = 12 * 128, }; -#define AIC31XX_NUM_SUPPLIES 6 -static const char * const aic31xx_supply_names[AIC31XX_NUM_SUPPLIES] = { +static const char * const aic31xx_supply_names[] = { "HPVDD", "SPRVDD", "SPLVDD", @@ -146,6 +145,8 @@ static const char * const aic31xx_supply_names[AIC31XX_NUM_SUPPLIES] = { "DVDD", }; +#define AIC31XX_NUM_SUPPLIES ARRAY_SIZE(aic31xx_supply_names) + struct aic31xx_disable_nb { struct notifier_block nb; struct aic31xx_priv *aic31xx; @@ -177,7 +178,7 @@ struct aic31xx_rate_divs { u8 madc; }; -/* ADC dividers can be disabled by cofiguring them to 0 */ +/* ADC dividers can be disabled by configuring them to 0 */ static const struct aic31xx_rate_divs aic31xx_divs[] = { /* mclk/p rate pll: j d dosr ndac mdac aors nadc madc */ /* 8k rate */ @@ -832,11 +833,17 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, dev_dbg(codec->dev, "pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n", - aic31xx_divs[i].pll_j, aic31xx_divs[i].pll_d, - aic31xx->p_div, aic31xx_divs[i].dosr, - aic31xx_divs[i].ndac, aic31xx_divs[i].mdac, - aic31xx_divs[i].aosr, aic31xx_divs[i].nadc, - aic31xx_divs[i].madc, bclk_n); + aic31xx_divs[i].pll_j, + aic31xx_divs[i].pll_d, + aic31xx->p_div, + aic31xx_divs[i].dosr, + aic31xx_divs[i].ndac, + aic31xx_divs[i].mdac, + aic31xx_divs[i].aosr, + aic31xx_divs[i].nadc, + aic31xx_divs[i].madc, + bclk_n + ); return 0; } @@ -973,8 +980,9 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n", __func__, clk_id, freq, dir); - for (i = 1; freq/i > 20000000 && i < 8; i++) - ; + for (i = 1; i < 8; i++) + if (freq / i <= 20000000) + break; if (freq/i > 20000000) { dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n", __func__, freq); @@ -982,9 +990,9 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, } aic31xx->p_div = i; - for (i = 0; i < ARRAY_SIZE(aic31xx_divs) && - aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++) - ; + for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) + if (aic31xx_divs[i].mclk_p == freq / aic31xx->p_div) + break; if (i == ARRAY_SIZE(aic31xx_divs)) { dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n", __func__, freq); @@ -996,6 +1004,7 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, clk_id << AIC31XX_PLL_CLKIN_SHIFT); aic31xx->sysclk = freq; + return 0; } @@ -1057,7 +1066,7 @@ static void aic31xx_clk_off(struct snd_soc_codec *codec) static int aic31xx_power_on(struct snd_soc_codec *codec) { struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); - int ret = 0; + int ret; ret = regulator_bulk_enable(ARRAY_SIZE(aic31xx->supplies), aic31xx->supplies); @@ -1070,7 +1079,7 @@ static int aic31xx_power_on(struct snd_soc_codec *codec) } regcache_cache_only(aic31xx->regmap, false); ret = regcache_sync(aic31xx->regmap); - if (ret != 0) { + if (ret) { dev_err(codec->dev, "Failed to restore cache: %d\n", ret); regcache_cache_only(aic31xx->regmap, true); @@ -1078,6 +1087,7 @@ static int aic31xx_power_on(struct snd_soc_codec *codec) aic31xx->supplies); return ret; } + return 0; } @@ -1126,14 +1136,11 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec, static int aic31xx_codec_probe(struct snd_soc_codec *codec) { - int ret = 0; struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); - int i; + int i, ret; dev_dbg(aic31xx->dev, "## %s\n", __func__); - aic31xx = snd_soc_codec_get_drvdata(codec); - aic31xx->codec = codec; for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) { @@ -1158,8 +1165,10 @@ static int aic31xx_codec_probe(struct snd_soc_codec *codec) return ret; ret = aic31xx_add_widgets(codec); + if (ret) + return ret; - return ret; + return 0; } static int aic31xx_codec_remove(struct snd_soc_codec *codec) @@ -1322,10 +1331,12 @@ static int aic31xx_device_init(struct aic31xx_priv *aic31xx) ret = devm_regulator_bulk_get(aic31xx->dev, ARRAY_SIZE(aic31xx->supplies), aic31xx->supplies); - if (ret != 0) + if (ret) { dev_err(aic31xx->dev, "Failed to request supplies: %d\n", ret); + return ret; + } - return ret; + return 0; } static int aic31xx_i2c_probe(struct i2c_client *i2c, @@ -1333,18 +1344,15 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, { struct aic31xx_priv *aic31xx; int ret; - const struct regmap_config *regmap_config; dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__, id->name, (int) id->driver_data); - regmap_config = &aic31xx_i2c_regmap; - aic31xx = devm_kzalloc(&i2c->dev, sizeof(*aic31xx), GFP_KERNEL); - if (aic31xx == NULL) + if (!aic31xx) return -ENOMEM; - aic31xx->regmap = devm_regmap_init_i2c(i2c, regmap_config); + aic31xx->regmap = devm_regmap_init_i2c(i2c, &aic31xx_i2c_regmap); if (IS_ERR(aic31xx->regmap)) { ret = PTR_ERR(aic31xx->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", @@ -1400,7 +1408,6 @@ static struct i2c_driver aic31xx_i2c_driver = { .remove = aic31xx_i2c_remove, .id_table = aic31xx_i2c_id, }; - module_i2c_driver(aic31xx_i2c_driver); MODULE_AUTHOR("Jyri Sarha "); -- cgit v1.2.3 From 12eb4d66ba2e14072b54f37f5a4a6f70457e228a Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 15:32:47 -0600 Subject: ASoC: tlv320aic31xx: Reformat header file using GENMASK and BIT macros We also move the comments describing the registers to after the register definition to remove non-uniform vertical white-space, this makes cross-referencing with the datasheet much easier. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.h | 320 ++++++++++++++++----------------------- 1 file changed, 133 insertions(+), 187 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 6efea0485392..15ac7cba86fe 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -10,20 +10,21 @@ #define AIC31XX_RATES SNDRV_PCM_RATE_8000_192000 -#define AIC31XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ - | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE \ - | SNDRV_PCM_FMTBIT_S32_LE) +#define AIC31XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) - -#define AIC31XX_STEREO_CLASS_D_BIT 0x1 -#define AIC31XX_MINIDSP_BIT 0x2 -#define DAC31XX_BIT 0x4 +#define AIC31XX_STEREO_CLASS_D_BIT BIT(1) +#define AIC31XX_MINIDSP_BIT BIT(2) +#define DAC31XX_BIT BIT(3) enum aic31xx_type { AIC3100 = 0, AIC3110 = AIC31XX_STEREO_CLASS_D_BIT, AIC3120 = AIC31XX_MINIDSP_BIT, - AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT), + AIC3111 = AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT, DAC3100 = DAC31XX_BIT, DAC3101 = DAC31XX_BIT | AIC31XX_STEREO_CLASS_D_BIT, }; @@ -36,222 +37,167 @@ struct aic31xx_pdata { #define AIC31XX_REG(page, reg) ((page * 128) + reg) -/* Page Control Register */ -#define AIC31XX_PAGECTL AIC31XX_REG(0, 0) +#define AIC31XX_PAGECTL AIC31XX_REG(0, 0) /* Page Control Register */ /* Page 0 Registers */ -/* Software reset register */ -#define AIC31XX_RESET AIC31XX_REG(0, 1) -/* OT FLAG register */ -#define AIC31XX_OT_FLAG AIC31XX_REG(0, 3) -/* Clock clock Gen muxing, Multiplexers*/ -#define AIC31XX_CLKMUX AIC31XX_REG(0, 4) -/* PLL P and R-VAL register */ -#define AIC31XX_PLLPR AIC31XX_REG(0, 5) -/* PLL J-VAL register */ -#define AIC31XX_PLLJ AIC31XX_REG(0, 6) -/* PLL D-VAL MSB register */ -#define AIC31XX_PLLDMSB AIC31XX_REG(0, 7) -/* PLL D-VAL LSB register */ -#define AIC31XX_PLLDLSB AIC31XX_REG(0, 8) -/* DAC NDAC_VAL register*/ -#define AIC31XX_NDAC AIC31XX_REG(0, 11) -/* DAC MDAC_VAL register */ -#define AIC31XX_MDAC AIC31XX_REG(0, 12) -/* DAC OSR setting register 1, MSB value */ -#define AIC31XX_DOSRMSB AIC31XX_REG(0, 13) -/* DAC OSR setting register 2, LSB value */ -#define AIC31XX_DOSRLSB AIC31XX_REG(0, 14) +#define AIC31XX_RESET AIC31XX_REG(0, 1) /* Software reset register */ +#define AIC31XX_OT_FLAG AIC31XX_REG(0, 3) /* OT FLAG register */ +#define AIC31XX_CLKMUX AIC31XX_REG(0, 4) /* Clock clock Gen muxing, Multiplexers*/ +#define AIC31XX_PLLPR AIC31XX_REG(0, 5) /* PLL P and R-VAL register */ +#define AIC31XX_PLLJ AIC31XX_REG(0, 6) /* PLL J-VAL register */ +#define AIC31XX_PLLDMSB AIC31XX_REG(0, 7) /* PLL D-VAL MSB register */ +#define AIC31XX_PLLDLSB AIC31XX_REG(0, 8) /* PLL D-VAL LSB register */ +#define AIC31XX_NDAC AIC31XX_REG(0, 11) /* DAC NDAC_VAL register*/ +#define AIC31XX_MDAC AIC31XX_REG(0, 12) /* DAC MDAC_VAL register */ +#define AIC31XX_DOSRMSB AIC31XX_REG(0, 13) /* DAC OSR setting register 1, MSB value */ +#define AIC31XX_DOSRLSB AIC31XX_REG(0, 14) /* DAC OSR setting register 2, LSB value */ #define AIC31XX_MINI_DSP_INPOL AIC31XX_REG(0, 16) -/* Clock setting register 8, PLL */ -#define AIC31XX_NADC AIC31XX_REG(0, 18) -/* Clock setting register 9, PLL */ -#define AIC31XX_MADC AIC31XX_REG(0, 19) -/* ADC Oversampling (AOSR) Register */ -#define AIC31XX_AOSR AIC31XX_REG(0, 20) -/* Clock setting register 9, Multiplexers */ -#define AIC31XX_CLKOUTMUX AIC31XX_REG(0, 25) -/* Clock setting register 10, CLOCKOUT M divider value */ -#define AIC31XX_CLKOUTMVAL AIC31XX_REG(0, 26) -/* Audio Interface Setting Register 1 */ -#define AIC31XX_IFACE1 AIC31XX_REG(0, 27) -/* Audio Data Slot Offset Programming */ -#define AIC31XX_DATA_OFFSET AIC31XX_REG(0, 28) -/* Audio Interface Setting Register 2 */ -#define AIC31XX_IFACE2 AIC31XX_REG(0, 29) -/* Clock setting register 11, BCLK N Divider */ -#define AIC31XX_BCLKN AIC31XX_REG(0, 30) -/* Audio Interface Setting Register 3, Secondary Audio Interface */ -#define AIC31XX_IFACESEC1 AIC31XX_REG(0, 31) -/* Audio Interface Setting Register 4 */ -#define AIC31XX_IFACESEC2 AIC31XX_REG(0, 32) -/* Audio Interface Setting Register 5 */ -#define AIC31XX_IFACESEC3 AIC31XX_REG(0, 33) -/* I2C Bus Condition */ -#define AIC31XX_I2C AIC31XX_REG(0, 34) -/* ADC FLAG */ -#define AIC31XX_ADCFLAG AIC31XX_REG(0, 36) -/* DAC Flag Registers */ -#define AIC31XX_DACFLAG1 AIC31XX_REG(0, 37) +#define AIC31XX_NADC AIC31XX_REG(0, 18) /* Clock setting register 8, PLL */ +#define AIC31XX_MADC AIC31XX_REG(0, 19) /* Clock setting register 9, PLL */ +#define AIC31XX_AOSR AIC31XX_REG(0, 20) /* ADC Oversampling (AOSR) Register */ +#define AIC31XX_CLKOUTMUX AIC31XX_REG(0, 25) /* Clock setting register 9, Multiplexers */ +#define AIC31XX_CLKOUTMVAL AIC31XX_REG(0, 26) /* Clock setting register 10, CLOCKOUT M divider value */ +#define AIC31XX_IFACE1 AIC31XX_REG(0, 27) /* Audio Interface Setting Register 1 */ +#define AIC31XX_DATA_OFFSET AIC31XX_REG(0, 28) /* Audio Data Slot Offset Programming */ +#define AIC31XX_IFACE2 AIC31XX_REG(0, 29) /* Audio Interface Setting Register 2 */ +#define AIC31XX_BCLKN AIC31XX_REG(0, 30) /* Clock setting register 11, BCLK N Divider */ +#define AIC31XX_IFACESEC1 AIC31XX_REG(0, 31) /* Audio Interface Setting Register 3, Secondary Audio Interface */ +#define AIC31XX_IFACESEC2 AIC31XX_REG(0, 32) /* Audio Interface Setting Register 4 */ +#define AIC31XX_IFACESEC3 AIC31XX_REG(0, 33) /* Audio Interface Setting Register 5 */ +#define AIC31XX_I2C AIC31XX_REG(0, 34) /* I2C Bus Condition */ +#define AIC31XX_ADCFLAG AIC31XX_REG(0, 36) /* ADC FLAG */ +#define AIC31XX_DACFLAG1 AIC31XX_REG(0, 37) /* DAC Flag Registers */ #define AIC31XX_DACFLAG2 AIC31XX_REG(0, 38) -/* Sticky Interrupt flag (overflow) */ -#define AIC31XX_OFFLAG AIC31XX_REG(0, 39) -/* Sticy DAC Interrupt flags */ -#define AIC31XX_INTRDACFLAG AIC31XX_REG(0, 44) -/* Sticy ADC Interrupt flags */ -#define AIC31XX_INTRADCFLAG AIC31XX_REG(0, 45) -/* DAC Interrupt flags 2 */ -#define AIC31XX_INTRDACFLAG2 AIC31XX_REG(0, 46) -/* ADC Interrupt flags 2 */ -#define AIC31XX_INTRADCFLAG2 AIC31XX_REG(0, 47) -/* INT1 interrupt control */ -#define AIC31XX_INT1CTRL AIC31XX_REG(0, 48) -/* INT2 interrupt control */ -#define AIC31XX_INT2CTRL AIC31XX_REG(0, 49) -/* GPIO1 control */ -#define AIC31XX_GPIO1 AIC31XX_REG(0, 51) - +#define AIC31XX_OFFLAG AIC31XX_REG(0, 39) /* Sticky Interrupt flag (overflow) */ +#define AIC31XX_INTRDACFLAG AIC31XX_REG(0, 44) /* Sticy DAC Interrupt flags */ +#define AIC31XX_INTRADCFLAG AIC31XX_REG(0, 45) /* Sticy ADC Interrupt flags */ +#define AIC31XX_INTRDACFLAG2 AIC31XX_REG(0, 46) /* DAC Interrupt flags 2 */ +#define AIC31XX_INTRADCFLAG2 AIC31XX_REG(0, 47) /* ADC Interrupt flags 2 */ +#define AIC31XX_INT1CTRL AIC31XX_REG(0, 48) /* INT1 interrupt control */ +#define AIC31XX_INT2CTRL AIC31XX_REG(0, 49) /* INT2 interrupt control */ +#define AIC31XX_GPIO1 AIC31XX_REG(0, 51) /* GPIO1 control */ #define AIC31XX_DACPRB AIC31XX_REG(0, 60) -/* ADC Instruction Set Register */ -#define AIC31XX_ADCPRB AIC31XX_REG(0, 61) -/* DAC channel setup register */ -#define AIC31XX_DACSETUP AIC31XX_REG(0, 63) -/* DAC Mute and volume control register */ -#define AIC31XX_DACMUTE AIC31XX_REG(0, 64) -/* Left DAC channel digital volume control */ -#define AIC31XX_LDACVOL AIC31XX_REG(0, 65) -/* Right DAC channel digital volume control */ -#define AIC31XX_RDACVOL AIC31XX_REG(0, 66) -/* Headset detection */ -#define AIC31XX_HSDETECT AIC31XX_REG(0, 67) -/* ADC Digital Mic */ -#define AIC31XX_ADCSETUP AIC31XX_REG(0, 81) -/* ADC Digital Volume Control Fine Adjust */ -#define AIC31XX_ADCFGA AIC31XX_REG(0, 82) -/* ADC Digital Volume Control Coarse Adjust */ -#define AIC31XX_ADCVOL AIC31XX_REG(0, 83) - +#define AIC31XX_ADCPRB AIC31XX_REG(0, 61) /* ADC Instruction Set Register */ +#define AIC31XX_DACSETUP AIC31XX_REG(0, 63) /* DAC channel setup register */ +#define AIC31XX_DACMUTE AIC31XX_REG(0, 64) /* DAC Mute and volume control register */ +#define AIC31XX_LDACVOL AIC31XX_REG(0, 65) /* Left DAC channel digital volume control */ +#define AIC31XX_RDACVOL AIC31XX_REG(0, 66) /* Right DAC channel digital volume control */ +#define AIC31XX_HSDETECT AIC31XX_REG(0, 67) /* Headset detection */ +#define AIC31XX_ADCSETUP AIC31XX_REG(0, 81) /* ADC Digital Mic */ +#define AIC31XX_ADCFGA AIC31XX_REG(0, 82) /* ADC Digital Volume Control Fine Adjust */ +#define AIC31XX_ADCVOL AIC31XX_REG(0, 83) /* ADC Digital Volume Control Coarse Adjust */ /* Page 1 Registers */ -/* Headphone drivers */ -#define AIC31XX_HPDRIVER AIC31XX_REG(1, 31) -/* Class-D Speakear Amplifier */ -#define AIC31XX_SPKAMP AIC31XX_REG(1, 32) -/* HP Output Drivers POP Removal Settings */ -#define AIC31XX_HPPOP AIC31XX_REG(1, 33) -/* Output Driver PGA Ramp-Down Period Control */ -#define AIC31XX_SPPGARAMP AIC31XX_REG(1, 34) -/* DAC_L and DAC_R Output Mixer Routing */ -#define AIC31XX_DACMIXERROUTE AIC31XX_REG(1, 35) -/* Left Analog Vol to HPL */ -#define AIC31XX_LANALOGHPL AIC31XX_REG(1, 36) -/* Right Analog Vol to HPR */ -#define AIC31XX_RANALOGHPR AIC31XX_REG(1, 37) -/* Left Analog Vol to SPL */ -#define AIC31XX_LANALOGSPL AIC31XX_REG(1, 38) -/* Right Analog Vol to SPR */ -#define AIC31XX_RANALOGSPR AIC31XX_REG(1, 39) -/* HPL Driver */ -#define AIC31XX_HPLGAIN AIC31XX_REG(1, 40) -/* HPR Driver */ -#define AIC31XX_HPRGAIN AIC31XX_REG(1, 41) -/* SPL Driver */ -#define AIC31XX_SPLGAIN AIC31XX_REG(1, 42) -/* SPR Driver */ -#define AIC31XX_SPRGAIN AIC31XX_REG(1, 43) -/* HP Driver Control */ -#define AIC31XX_HPCONTROL AIC31XX_REG(1, 44) -/* MIC Bias Control */ -#define AIC31XX_MICBIAS AIC31XX_REG(1, 46) -/* MIC PGA*/ -#define AIC31XX_MICPGA AIC31XX_REG(1, 47) -/* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */ -#define AIC31XX_MICPGAPI AIC31XX_REG(1, 48) -/* ADC Input Selection for M-Terminal */ -#define AIC31XX_MICPGAMI AIC31XX_REG(1, 49) -/* Input CM Settings */ -#define AIC31XX_MICPGACM AIC31XX_REG(1, 50) - -/* Bits, masks and shifts */ +#define AIC31XX_HPDRIVER AIC31XX_REG(1, 31) /* Headphone drivers */ +#define AIC31XX_SPKAMP AIC31XX_REG(1, 32) /* Class-D Speakear Amplifier */ +#define AIC31XX_HPPOP AIC31XX_REG(1, 33) /* HP Output Drivers POP Removal Settings */ +#define AIC31XX_SPPGARAMP AIC31XX_REG(1, 34) /* Output Driver PGA Ramp-Down Period Control */ +#define AIC31XX_DACMIXERROUTE AIC31XX_REG(1, 35) /* DAC_L and DAC_R Output Mixer Routing */ +#define AIC31XX_LANALOGHPL AIC31XX_REG(1, 36) /* Left Analog Vol to HPL */ +#define AIC31XX_RANALOGHPR AIC31XX_REG(1, 37) /* Right Analog Vol to HPR */ +#define AIC31XX_LANALOGSPL AIC31XX_REG(1, 38) /* Left Analog Vol to SPL */ +#define AIC31XX_RANALOGSPR AIC31XX_REG(1, 39) /* Right Analog Vol to SPR */ +#define AIC31XX_HPLGAIN AIC31XX_REG(1, 40) /* HPL Driver */ +#define AIC31XX_HPRGAIN AIC31XX_REG(1, 41) /* HPR Driver */ +#define AIC31XX_SPLGAIN AIC31XX_REG(1, 42) /* SPL Driver */ +#define AIC31XX_SPRGAIN AIC31XX_REG(1, 43) /* SPR Driver */ +#define AIC31XX_HPCONTROL AIC31XX_REG(1, 44) /* HP Driver Control */ +#define AIC31XX_MICBIAS AIC31XX_REG(1, 46) /* MIC Bias Control */ +#define AIC31XX_MICPGA AIC31XX_REG(1, 47) /* MIC PGA*/ +#define AIC31XX_MICPGAPI AIC31XX_REG(1, 48) /* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */ +#define AIC31XX_MICPGAMI AIC31XX_REG(1, 49) /* ADC Input Selection for M-Terminal */ +#define AIC31XX_MICPGACM AIC31XX_REG(1, 50) /* Input CM Settings */ + +/* Bits, masks, and shifts */ /* AIC31XX_CLKMUX */ -#define AIC31XX_PLL_CLKIN_MASK 0x0c -#define AIC31XX_PLL_CLKIN_SHIFT 2 -#define AIC31XX_PLL_CLKIN_MCLK 0 -#define AIC31XX_CODEC_CLKIN_MASK 0x03 -#define AIC31XX_CODEC_CLKIN_SHIFT 0 -#define AIC31XX_CODEC_CLKIN_PLL 3 -#define AIC31XX_CODEC_CLKIN_BCLK 1 - -/* AIC31XX_PLLPR, AIC31XX_NDAC, AIC31XX_MDAC, AIC31XX_NADC, AIC31XX_MADC, - AIC31XX_BCLKN */ -#define AIC31XX_PLL_MASK 0x7f -#define AIC31XX_PM_MASK 0x80 +#define AIC31XX_PLL_CLKIN_MASK GENMASK(3, 2) +#define AIC31XX_PLL_CLKIN_SHIFT (2) +#define AIC31XX_PLL_CLKIN_MCLK 0x00 +#define AIC31XX_PLL_CLKIN_BCKL 0x01 +#define AIC31XX_PLL_CLKIN_GPIO1 0x02 +#define AIC31XX_PLL_CLKIN_DIN 0x03 +#define AIC31XX_CODEC_CLKIN_MASK GENMASK(1, 0) +#define AIC31XX_CODEC_CLKIN_SHIFT (0) +#define AIC31XX_CODEC_CLKIN_MCLK 0x00 +#define AIC31XX_CODEC_CLKIN_BCLK 0x01 +#define AIC31XX_CODEC_CLKIN_GPIO1 0x02 +#define AIC31XX_CODEC_CLKIN_PLL 0x03 + +/* AIC31XX_PLLPR */ +/* AIC31XX_NDAC */ +/* AIC31XX_MDAC */ +/* AIC31XX_NADC */ +/* AIC31XX_MADC */ +/* AIC31XX_BCLKN */ +#define AIC31XX_PLL_MASK GENMASK(6, 0) +#define AIC31XX_PM_MASK BIT(7) /* AIC31XX_IFACE1 */ -#define AIC31XX_WORD_LEN_16BITS 0x00 -#define AIC31XX_WORD_LEN_20BITS 0x01 -#define AIC31XX_WORD_LEN_24BITS 0x02 -#define AIC31XX_WORD_LEN_32BITS 0x03 -#define AIC31XX_IFACE1_DATALEN_MASK 0x30 -#define AIC31XX_IFACE1_DATALEN_SHIFT (4) -#define AIC31XX_IFACE1_DATATYPE_MASK 0xC0 +#define AIC31XX_IFACE1_DATATYPE_MASK GENMASK(7, 6) #define AIC31XX_IFACE1_DATATYPE_SHIFT (6) #define AIC31XX_I2S_MODE 0x00 #define AIC31XX_DSP_MODE 0x01 #define AIC31XX_RIGHT_JUSTIFIED_MODE 0x02 #define AIC31XX_LEFT_JUSTIFIED_MODE 0x03 -#define AIC31XX_IFACE1_MASTER_MASK 0x0C -#define AIC31XX_BCLK_MASTER 0x08 -#define AIC31XX_WCLK_MASTER 0x04 +#define AIC31XX_IFACE1_DATALEN_MASK GENMASK(5, 4) +#define AIC31XX_IFACE1_DATALEN_SHIFT (4) +#define AIC31XX_WORD_LEN_16BITS 0x00 +#define AIC31XX_WORD_LEN_20BITS 0x01 +#define AIC31XX_WORD_LEN_24BITS 0x02 +#define AIC31XX_WORD_LEN_32BITS 0x03 +#define AIC31XX_IFACE1_MASTER_MASK GENMASK(3, 2) +#define AIC31XX_BCLK_MASTER BIT(2) +#define AIC31XX_WCLK_MASTER BIT(3) /* AIC31XX_DATA_OFFSET */ -#define AIC31XX_DATA_OFFSET_MASK 0xFF +#define AIC31XX_DATA_OFFSET_MASK GENMASK(7, 0) /* AIC31XX_IFACE2 */ -#define AIC31XX_BCLKINV_MASK 0x08 -#define AIC31XX_BDIVCLK_MASK 0x03 +#define AIC31XX_BCLKINV_MASK BIT(3) +#define AIC31XX_BDIVCLK_MASK GENMASK(1, 0) #define AIC31XX_DAC2BCLK 0x00 #define AIC31XX_DACMOD2BCLK 0x01 #define AIC31XX_ADC2BCLK 0x02 #define AIC31XX_ADCMOD2BCLK 0x03 /* AIC31XX_ADCFLAG */ -#define AIC31XX_ADCPWRSTATUS_MASK 0x40 +#define AIC31XX_ADCPWRSTATUS_MASK BIT(6) /* AIC31XX_DACFLAG1 */ -#define AIC31XX_LDACPWRSTATUS_MASK 0x80 -#define AIC31XX_RDACPWRSTATUS_MASK 0x08 -#define AIC31XX_HPLDRVPWRSTATUS_MASK 0x20 -#define AIC31XX_HPRDRVPWRSTATUS_MASK 0x02 -#define AIC31XX_SPLDRVPWRSTATUS_MASK 0x10 -#define AIC31XX_SPRDRVPWRSTATUS_MASK 0x01 +#define AIC31XX_LDACPWRSTATUS_MASK BIT(7) +#define AIC31XX_HPLDRVPWRSTATUS_MASK BIT(5) +#define AIC31XX_SPLDRVPWRSTATUS_MASK BIT(4) +#define AIC31XX_RDACPWRSTATUS_MASK BIT(3) +#define AIC31XX_HPRDRVPWRSTATUS_MASK BIT(1) +#define AIC31XX_SPRDRVPWRSTATUS_MASK BIT(0) /* AIC31XX_INTRDACFLAG */ -#define AIC31XX_HPSCDETECT_MASK 0x80 -#define AIC31XX_BUTTONPRESS_MASK 0x20 -#define AIC31XX_HSPLUG_MASK 0x10 -#define AIC31XX_LDRCTHRES_MASK 0x08 -#define AIC31XX_RDRCTHRES_MASK 0x04 -#define AIC31XX_DACSINT_MASK 0x02 -#define AIC31XX_DACAINT_MASK 0x01 +#define AIC31XX_HPLSCDETECT BIT(7) +#define AIC31XX_HPRSCDETECT BIT(6) +#define AIC31XX_BUTTONPRESS BIT(5) +#define AIC31XX_HSPLUG BIT(4) +#define AIC31XX_LDRCTHRES BIT(3) +#define AIC31XX_RDRCTHRES BIT(2) +#define AIC31XX_DACSINT BIT(1) +#define AIC31XX_DACAINT BIT(0) /* AIC31XX_INT1CTRL */ -#define AIC31XX_HSPLUGDET_MASK 0x80 -#define AIC31XX_BUTTONPRESSDET_MASK 0x40 -#define AIC31XX_DRCTHRES_MASK 0x20 -#define AIC31XX_AGCNOISE_MASK 0x10 -#define AIC31XX_OC_MASK 0x08 -#define AIC31XX_ENGINE_MASK 0x04 +#define AIC31XX_HSPLUGDET BIT(7) +#define AIC31XX_BUTTONPRESSDET BIT(6) +#define AIC31XX_DRCTHRES BIT(5) +#define AIC31XX_AGCNOISE BIT(4) +#define AIC31XX_SC BIT(3) +#define AIC31XX_ENGINE BIT(2) /* AIC31XX_DACSETUP */ -#define AIC31XX_SOFTSTEP_MASK 0x03 +#define AIC31XX_SOFTSTEP_MASK GENMASK(1, 0) /* AIC31XX_DACMUTE */ -#define AIC31XX_DACMUTE_MASK 0x0C +#define AIC31XX_DACMUTE_MASK GENMASK(3, 2) /* AIC31XX_MICBIAS */ -#define AIC31XX_MICBIAS_MASK 0x03 -#define AIC31XX_MICBIAS_SHIFT 0 +#define AIC31XX_MICBIAS_MASK GENMASK(1, 0) +#define AIC31XX_MICBIAS_SHIFT 0 #endif /* _TLV320AIC31XX_H */ -- cgit v1.2.3 From e88c3881361cee9b778bf4e4ded43da7a0917ce1 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 15:32:48 -0600 Subject: ASoC: tlv320aic31xx: Merge init function into probe The function aic31xx_device_init() is only called from probe and does nothing that logically shouldn't be in probe, remove this unneeded function call and move its code into probe where it was called. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 55 ++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 07c014501e5e..c84febd991a0 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1302,9 +1302,29 @@ static const struct acpi_device_id aic31xx_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match); #endif -static int aic31xx_device_init(struct aic31xx_priv *aic31xx) +static int aic31xx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { - int ret, i; + struct aic31xx_priv *aic31xx; + int i, ret; + + dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__, + id->name, (int)id->driver_data); + + aic31xx = devm_kzalloc(&i2c->dev, sizeof(*aic31xx), GFP_KERNEL); + if (!aic31xx) + return -ENOMEM; + + aic31xx->regmap = devm_regmap_init_i2c(i2c, &aic31xx_i2c_regmap); + if (IS_ERR(aic31xx->regmap)) { + ret = PTR_ERR(aic31xx->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + aic31xx->dev = &i2c->dev; + + aic31xx->pdata.codec_type = id->driver_data; dev_set_drvdata(aic31xx->dev, aic31xx); @@ -1336,37 +1356,6 @@ static int aic31xx_device_init(struct aic31xx_priv *aic31xx) return ret; } - return 0; -} - -static int aic31xx_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct aic31xx_priv *aic31xx; - int ret; - - dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__, - id->name, (int) id->driver_data); - - aic31xx = devm_kzalloc(&i2c->dev, sizeof(*aic31xx), GFP_KERNEL); - if (!aic31xx) - return -ENOMEM; - - aic31xx->regmap = devm_regmap_init_i2c(i2c, &aic31xx_i2c_regmap); - if (IS_ERR(aic31xx->regmap)) { - ret = PTR_ERR(aic31xx->regmap); - dev_err(&i2c->dev, "Failed to allocate register map: %d\n", - ret); - return ret; - } - aic31xx->dev = &i2c->dev; - - aic31xx->pdata.codec_type = id->driver_data; - - ret = aic31xx_device_init(aic31xx); - if (ret) - return ret; - if (aic31xx->pdata.codec_type & DAC31XX_BIT) return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx, -- cgit v1.2.3 From b6b247cd5e37560e410c88b108e7408dafe60c15 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 15:32:49 -0600 Subject: ASoC: tlv320aic31xx: Switch GPIO handling to use gpiod_* API Move to using newer gpiod_* GPIO handling functions. This simplifies the code and eases dropping platform data in the next patch. Also remember GPIO are active low, so set "1" to reset. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index c84febd991a0..ab03a19f6aaa 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -157,6 +157,7 @@ struct aic31xx_priv { u8 i2c_regs_status; struct device *dev; struct regmap *regmap; + struct gpio_desc *gpio_reset; struct aic31xx_pdata pdata; struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES]; @@ -1020,8 +1021,8 @@ static int aic31xx_regulator_event(struct notifier_block *nb, * Put codec to reset and as at least one of the * supplies was disabled. */ - if (gpio_is_valid(aic31xx->pdata.gpio_reset)) - gpio_set_value(aic31xx->pdata.gpio_reset, 0); + if (aic31xx->gpio_reset) + gpiod_set_value(aic31xx->gpio_reset, 1); regcache_mark_dirty(aic31xx->regmap); dev_dbg(aic31xx->dev, "## %s: DISABLE received\n", __func__); @@ -1073,8 +1074,8 @@ static int aic31xx_power_on(struct snd_soc_codec *codec) if (ret) return ret; - if (gpio_is_valid(aic31xx->pdata.gpio_reset)) { - gpio_set_value(aic31xx->pdata.gpio_reset, 1); + if (aic31xx->gpio_reset) { + gpiod_set_value(aic31xx->gpio_reset, 0); udelay(100); } regcache_cache_only(aic31xx->regmap, false); @@ -1334,15 +1335,11 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, else if (aic31xx->dev->of_node) aic31xx_pdata_from_of(aic31xx); - if (aic31xx->pdata.gpio_reset) { - ret = devm_gpio_request_one(aic31xx->dev, - aic31xx->pdata.gpio_reset, - GPIOF_OUT_INIT_HIGH, - "aic31xx-reset-pin"); - if (ret < 0) { - dev_err(aic31xx->dev, "not able to acquire gpio\n"); - return ret; - } + aic31xx->gpio_reset = devm_gpiod_get_optional(aic31xx->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(aic31xx->gpio_reset)) { + dev_err(aic31xx->dev, "not able to acquire gpio\n"); + return PTR_ERR(aic31xx->gpio_reset); } for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) -- cgit v1.2.3 From c6b8c779213dfe2a31e12400b1a2cf2a9a843236 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 15:32:52 -0600 Subject: ASoC: tlv320aic31xx: Check clock and divider before division If our set_sysclk DAI callback has not been called yet p_div will be 0 and dividing by this will cause an error. Print an error message and leave before this. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index ab03a19f6aaa..05e6d194d6a9 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -754,11 +754,17 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, { struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); int bclk_score = snd_soc_params_to_frame_size(params); - int mclk_p = aic31xx->sysclk / aic31xx->p_div; + int mclk_p; int bclk_n = 0; int match = -1; int i; + if (!aic31xx->sysclk || !aic31xx->p_div) { + dev_err(codec->dev, "Master clock not supplied\n"); + return -EINVAL; + } + mclk_p = aic31xx->sysclk / aic31xx->p_div; + /* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */ snd_soc_update_bits(codec, AIC31XX_CLKMUX, AIC31XX_CODEC_CLKIN_MASK, AIC31XX_CODEC_CLKIN_PLL); -- cgit v1.2.3 From 77f8b3cfc33cd4231cc2748bcac9f43b9eea546c Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 15:32:53 -0600 Subject: ASoC: tlv320aic31xx: Add CODEC clock slave support This CODEC supports being the WCLK and/or BCLK slave, add support for this here. Also make the alert into an error as alert is more urgent than needed here and is rarely used. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 05e6d194d6a9..d77cc36d7360 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -925,8 +925,16 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, case SND_SOC_DAIFMT_CBM_CFM: iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER; break; + case SND_SOC_DAIFMT_CBS_CFM: + iface_reg1 |= AIC31XX_WCLK_MASTER; + break; + case SND_SOC_DAIFMT_CBM_CFS: + iface_reg1 |= AIC31XX_BCLK_MASTER; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; default: - dev_alert(codec->dev, "Invalid DAI master/slave interface\n"); + dev_err(codec->dev, "Invalid DAI master/slave interface\n"); return -EINVAL; } -- cgit v1.2.3 From dcb407b257af06fa58b0544ec01ec9e0d3927e02 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 15:32:54 -0600 Subject: ASoC: tlv320aic31xx: Handle inverted BCLK in non-DSP modes Currently BCLK inverting is only handled when the DAI format is DSP, but the BCLK may be inverted in any supported mode. Without this using this CODEC in any other mode than DSP with the BCLK inverted leads to bad sampling timing and very poor audio quality. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index d77cc36d7360..38fd6ea275fb 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -938,6 +938,18 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } + /* signal polarity */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + iface_reg2 |= AIC31XX_BCLKINV_MASK; + break; + default: + dev_err(codec->dev, "Invalid DAI clock signal polarity\n"); + return -EINVAL; + } + /* interface format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -945,16 +957,12 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, case SND_SOC_DAIFMT_DSP_A: dsp_a_val = 0x1; /* fall through */ case SND_SOC_DAIFMT_DSP_B: - /* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - iface_reg2 |= AIC31XX_BCLKINV_MASK; - break; - case SND_SOC_DAIFMT_IB_NF: - break; - default: - return -EINVAL; - } + /* + * NOTE: This CODEC samples on the falling edge of BCLK in + * DSP mode, this is inverted compared to what most DAIs + * expect, so we invert for this mode + */ + iface_reg2 ^= AIC31XX_BCLKINV_MASK; iface_reg1 |= (AIC31XX_DSP_MODE << AIC31XX_IFACE1_DATATYPE_SHIFT); break; -- cgit v1.2.3 From c6766aae8e08008a8860271448f22ab71cb848b4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Nov 2017 06:03:32 +0000 Subject: ASoC: use snd_soc_component_init_regmap() on wm8998 To setup regmap, ALSA SoC has snd_soc_component_init_regmap() and .get_regmap. But these are duplicated feature. Let's use snd_soc_component_init_regmap() and remove .get_regmap Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/wm8998.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 2d211dbe7422..1288e1f67dcf 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -1275,9 +1275,11 @@ static int wm8998_codec_probe(struct snd_soc_codec *codec) struct wm8998_priv *priv = snd_soc_codec_get_drvdata(codec); struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); + struct arizona *arizona = priv->core.arizona; int ret; - priv->core.arizona->dapm = dapm; + arizona->dapm = dapm; + snd_soc_codec_init_regmap(codec, arizona->regmap); ret = arizona_init_spk(codec); if (ret < 0) @@ -1313,17 +1315,9 @@ static unsigned int wm8998_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_5R, }; -static struct regmap *wm8998_get_regmap(struct device *dev) -{ - struct wm8998_priv *priv = dev_get_drvdata(dev); - - return priv->core.arizona->regmap; -} - static const struct snd_soc_codec_driver soc_codec_dev_wm8998 = { .probe = wm8998_codec_probe, .remove = wm8998_codec_remove, - .get_regmap = wm8998_get_regmap, .idle_bias_off = true, -- cgit v1.2.3 From 1e4a36afe04b8edd9affc41371822a79599b98e0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Nov 2017 06:03:48 +0000 Subject: ASoC: use snd_soc_component_init_regmap() on wm8997 To setup regmap, ALSA SoC has snd_soc_component_init_regmap() and .get_regmap. But these are duplicated feature. Let's use snd_soc_component_init_regmap() and remove .get_regmap Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/wm8997.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 77f512767273..cac9b3e7e15d 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -1062,8 +1062,11 @@ static int wm8997_codec_probe(struct snd_soc_codec *codec) struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->core.arizona; int ret; + snd_soc_codec_init_regmap(codec, arizona->regmap); + ret = arizona_init_spk(codec); if (ret < 0) return ret; @@ -1095,17 +1098,9 @@ static unsigned int wm8997_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_5R, }; -static struct regmap *wm8997_get_regmap(struct device *dev) -{ - struct wm8997_priv *priv = dev_get_drvdata(dev); - - return priv->core.arizona->regmap; -} - static const struct snd_soc_codec_driver soc_codec_dev_wm8997 = { .probe = wm8997_codec_probe, .remove = wm8997_codec_remove, - .get_regmap = wm8997_get_regmap, .idle_bias_off = true, -- cgit v1.2.3 From 5a81eb5356c87ad60f65378464ba92a7d645ce1d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Nov 2017 06:04:02 +0000 Subject: ASoC: use snd_soc_component_init_regmap() on wm8994 To setup regmap, ALSA SoC has snd_soc_component_init_regmap() and .get_regmap. But these are duplicated feature. Let's use snd_soc_component_init_regmap() and remove .get_regmap Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index f91b49e1ece3..21ffd6403173 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3993,6 +3993,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) unsigned int reg; int ret, i; + snd_soc_codec_init_regmap(codec, control->regmap); + wm8994->hubs.codec = codec; mutex_init(&wm8994->accdet_lock); @@ -4434,19 +4436,11 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) return 0; } -static struct regmap *wm8994_get_regmap(struct device *dev) -{ - struct wm8994 *control = dev_get_drvdata(dev->parent); - - return control->regmap; -} - static const struct snd_soc_codec_driver soc_codec_dev_wm8994 = { .probe = wm8994_codec_probe, .remove = wm8994_codec_remove, .suspend = wm8994_codec_suspend, .resume = wm8994_codec_resume, - .get_regmap = wm8994_get_regmap, .set_bias_level = wm8994_set_bias_level, }; -- cgit v1.2.3 From 74c76497946e1f15b51d603735eb8273ac89381e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Nov 2017 06:04:17 +0000 Subject: ASoC: use snd_soc_component_init_regmap() on wm8400 To setup regmap, ALSA SoC has snd_soc_component_init_regmap() and .get_regmap. But these are duplicated feature. Let's use snd_soc_component_init_regmap() and remove .get_regmap Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/wm8400.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 6c59fb933bd6..a36adf881bca 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -1285,6 +1285,7 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) if (priv == NULL) return -ENOMEM; + snd_soc_codec_init_regmap(codec, wm8400->regmap); snd_soc_codec_set_drvdata(codec, priv); priv->wm8400 = wm8400; @@ -1325,17 +1326,9 @@ static int wm8400_codec_remove(struct snd_soc_codec *codec) return 0; } -static struct regmap *wm8400_get_regmap(struct device *dev) -{ - struct wm8400 *wm8400 = dev_get_platdata(dev); - - return wm8400->regmap; -} - static const struct snd_soc_codec_driver soc_codec_dev_wm8400 = { .probe = wm8400_codec_probe, .remove = wm8400_codec_remove, - .get_regmap = wm8400_get_regmap, .set_bias_level = wm8400_set_bias_level, .suspend_bias_off = true, -- cgit v1.2.3 From 40b84884617d9f07663862770d2574a71e313bc7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Nov 2017 06:04:31 +0000 Subject: ASoC: use snd_soc_component_init_regmap() on wm8350 To setup regmap, ALSA SoC has snd_soc_component_init_regmap() and .get_regmap. But these are duplicated feature. Let's use snd_soc_component_init_regmap() and remove .get_regmap Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/wm8350.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 2efc5b41ad0f..fc79c6725d06 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1472,6 +1472,8 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec) GFP_KERNEL); if (priv == NULL) return -ENOMEM; + + snd_soc_codec_init_regmap(codec, wm8350->regmap); snd_soc_codec_set_drvdata(codec, priv); priv->wm8350 = wm8350; @@ -1580,17 +1582,9 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec) return 0; } -static struct regmap *wm8350_get_regmap(struct device *dev) -{ - struct wm8350 *wm8350 = dev_get_platdata(dev); - - return wm8350->regmap; -} - static const struct snd_soc_codec_driver soc_codec_dev_wm8350 = { .probe = wm8350_codec_probe, .remove = wm8350_codec_remove, - .get_regmap = wm8350_get_regmap, .set_bias_level = wm8350_set_bias_level, .suspend_bias_off = true, -- cgit v1.2.3 From 893d7cbea2fa259573e4ba36075e74f489f6dd28 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Nov 2017 06:04:45 +0000 Subject: ASoC: use snd_soc_component_init_regmap() on wm5110 To setup regmap, ALSA SoC has snd_soc_component_init_regmap() and .get_regmap. But these are duplicated feature. Let's use snd_soc_component_init_regmap() and remove .get_regmap Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/wm5110.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 6ed1e1f9ce51..fb0cf9c61f48 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2280,9 +2280,11 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->core.arizona; int i, ret; - priv->core.arizona->dapm = dapm; + arizona->dapm = dapm; + snd_soc_codec_init_regmap(codec, arizona->regmap); ret = arizona_init_spk(codec); if (ret < 0) @@ -2344,17 +2346,9 @@ static unsigned int wm5110_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_6R, }; -static struct regmap *wm5110_get_regmap(struct device *dev) -{ - struct wm5110_priv *priv = dev_get_drvdata(dev); - - return priv->core.arizona->regmap; -} - static const struct snd_soc_codec_driver soc_codec_dev_wm5110 = { .probe = wm5110_codec_probe, .remove = wm5110_codec_remove, - .get_regmap = wm5110_get_regmap, .idle_bias_off = true, -- cgit v1.2.3 From 2d6e28c368aabbdc841c44a2213a5ee16cfd5ae2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Nov 2017 06:05:01 +0000 Subject: ASoC: use snd_soc_component_init_regmap() on wm5102 To setup regmap, ALSA SoC has snd_soc_component_init_regmap() and .get_regmap. But these are duplicated feature. Let's use snd_soc_component_init_regmap() and remove .get_regmap Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/wm5102.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 4f0481d3c7a7..fc066caa1918 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1935,8 +1935,11 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->core.arizona; int ret; + snd_soc_codec_init_regmap(codec, arizona->regmap); + ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec); if (ret) return ret; @@ -1989,17 +1992,9 @@ static unsigned int wm5102_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_5R, }; -static struct regmap *wm5102_get_regmap(struct device *dev) -{ - struct wm5102_priv *priv = dev_get_drvdata(dev); - - return priv->core.arizona->regmap; -} - static const struct snd_soc_codec_driver soc_codec_dev_wm5102 = { .probe = wm5102_codec_probe, .remove = wm5102_codec_remove, - .get_regmap = wm5102_get_regmap, .idle_bias_off = true, -- cgit v1.2.3 From 3047ec50c3ebbe082217dc20ec0db4f3e5c7abea Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Nov 2017 06:05:15 +0000 Subject: ASoC: use snd_soc_component_init_regmap() on si476x To setup regmap, ALSA SoC has snd_soc_component_init_regmap() and .get_regmap. But these are duplicated feature. Let's use snd_soc_component_init_regmap() and remove .get_regmap Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/si476x.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 354dc0d64f11..7b91ee267b4e 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -231,14 +231,17 @@ static struct snd_soc_dai_driver si476x_dai = { .ops = &si476x_dai_ops, }; -static struct regmap *si476x_get_regmap(struct device *dev) +static int si476x_probe(struct snd_soc_component *component) { - return dev_get_regmap(dev->parent, NULL); + snd_soc_component_init_regmap(component, + dev_get_regmap(component->dev->parent, NULL)); + + return 0; } static const struct snd_soc_codec_driver soc_codec_dev_si476x = { - .get_regmap = si476x_get_regmap, .component_driver = { + .probe = si476x_probe, .dapm_widgets = si476x_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets), .dapm_routes = si476x_dapm_routes, -- cgit v1.2.3 From 33953d851d37f8b62b96d70fdccd35b62dffebe8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Nov 2017 06:05:31 +0000 Subject: ASoC: use snd_soc_component_init_regmap() on mc13783 To setup regmap, ALSA SoC has snd_soc_component_init_regmap() and .get_regmap. But these are duplicated feature. Let's use snd_soc_component_init_regmap() and remove .get_regmap Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/mc13783.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 4fd8d1dc4eef..be7a45f05bbf 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -610,6 +610,9 @@ static int mc13783_probe(struct snd_soc_codec *codec) { struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); + snd_soc_codec_init_regmap(codec, + dev_get_regmap(codec->dev->parent, NULL)); + /* these are the reset values */ mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893); mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX1, 0x00d35A); @@ -728,15 +731,9 @@ static struct snd_soc_dai_driver mc13783_dai_sync[] = { } }; -static struct regmap *mc13783_get_regmap(struct device *dev) -{ - return dev_get_regmap(dev->parent, NULL); -} - static const struct snd_soc_codec_driver soc_codec_dev_mc13783 = { .probe = mc13783_probe, .remove = mc13783_remove, - .get_regmap = mc13783_get_regmap, .component_driver = { .controls = mc13783_control_list, .num_controls = ARRAY_SIZE(mc13783_control_list), -- cgit v1.2.3 From 60e1780ef27c626c7eaabae6103a218102b6e6ba Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Nov 2017 06:05:46 +0000 Subject: ASoC: use snd_soc_component_init_regmap() on cq93vc To setup regmap, ALSA SoC has snd_soc_component_init_regmap() and .get_regmap. But these are duplicated feature. Let's use snd_soc_component_init_regmap() and remove .get_regmap Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/cq93vc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 6ed2cc374768..3bf93652bb31 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -121,17 +121,19 @@ static struct snd_soc_dai_driver cq93vc_dai = { .ops = &cq93vc_dai_ops, }; -static struct regmap *cq93vc_get_regmap(struct device *dev) +static int cq93vc_probe(struct snd_soc_component *component) { - struct davinci_vc *davinci_vc = dev->platform_data; + struct davinci_vc *davinci_vc = component->dev->platform_data; - return davinci_vc->regmap; + snd_soc_component_init_regmap(component, davinci_vc->regmap); + + return 0; } static const struct snd_soc_codec_driver soc_codec_dev_cq93vc = { .set_bias_level = cq93vc_set_bias_level, - .get_regmap = cq93vc_get_regmap, .component_driver = { + .probe = cq93vc_probe, .controls = cq93vc_snd_controls, .num_controls = ARRAY_SIZE(cq93vc_snd_controls), }, -- cgit v1.2.3 From ba8dd49f9431497c6b13514cfab3065b01057247 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Nov 2017 06:06:00 +0000 Subject: ASoC: use snd_soc_component_init_regmap() on cs47l24 To setup regmap, ALSA SoC has snd_soc_component_init_regmap() and .get_regmap. But these are duplicated feature. Let's use snd_soc_component_init_regmap() and remove .get_regmap Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l24.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 94c0209977d0..be2750680838 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1120,9 +1120,11 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec) struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->core.arizona; int ret; - priv->core.arizona->dapm = dapm; + arizona->dapm = dapm; + snd_soc_codec_init_regmap(codec, arizona->regmap); ret = arizona_init_spk(codec); if (ret < 0) @@ -1175,17 +1177,9 @@ static unsigned int cs47l24_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_4L, }; -static struct regmap *cs47l24_get_regmap(struct device *dev) -{ - struct cs47l24_priv *priv = dev_get_drvdata(dev); - - return priv->core.arizona->regmap; -} - static const struct snd_soc_codec_driver soc_codec_dev_cs47l24 = { .probe = cs47l24_codec_probe, .remove = cs47l24_codec_remove, - .get_regmap = cs47l24_get_regmap, .idle_bias_off = true, -- cgit v1.2.3 From 79b4885967cff17e0344b451e8fc4782013f0c9c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Nov 2017 06:06:15 +0000 Subject: ASoC: use snd_soc_component_init_regmap() on 88pm860x To setup regmap, ALSA SoC has snd_soc_component_init_regmap() and .get_regmap. But these are duplicated feature. Let's use snd_soc_component_init_regmap() and remove .get_regmap Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/88pm860x-codec.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 848c5fe49bc7..be8ea723dff9 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -1319,6 +1319,7 @@ static int pm860x_probe(struct snd_soc_codec *codec) int i, ret; pm860x->codec = codec; + snd_soc_codec_init_regmap(codec, pm860x->regmap); for (i = 0; i < 4; i++) { ret = request_threaded_irq(pm860x->irq[i], NULL, @@ -1348,18 +1349,10 @@ static int pm860x_remove(struct snd_soc_codec *codec) return 0; } -static struct regmap *pm860x_get_regmap(struct device *dev) -{ - struct pm860x_priv *pm860x = dev_get_drvdata(dev); - - return pm860x->regmap; -} - static const struct snd_soc_codec_driver soc_codec_dev_pm860x = { .probe = pm860x_probe, .remove = pm860x_remove, .set_bias_level = pm860x_set_bias_level, - .get_regmap = pm860x_get_regmap, .component_driver = { .controls = pm860x_snd_controls, -- cgit v1.2.3 From 42e193cdcb9e197e788638bd33bab3d1905815f6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Nov 2017 06:06:29 +0000 Subject: ASoC: use snd_soc_component_init_regmap() on msm8916 To setup regmap, ALSA SoC has snd_soc_component_init_regmap() and .get_regmap. But these are duplicated feature. Let's use snd_soc_component_init_regmap() and remove .get_regmap Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-analog.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 066ea2f4ce7b..44062bb7bf2f 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -712,6 +712,8 @@ static int pm8916_wcd_analog_probe(struct snd_soc_codec *codec) return err; } + snd_soc_codec_init_regmap(codec, + dev_get_regmap(codec->dev->parent, NULL)); snd_soc_codec_set_drvdata(codec, priv); priv->pmic_rev = snd_soc_read(codec, CDC_D_REVISION1); priv->codec_version = snd_soc_read(codec, CDC_D_PERPH_SUBTYPE); @@ -943,11 +945,6 @@ static int pm8916_wcd_analog_set_jack(struct snd_soc_codec *codec, return 0; } -static struct regmap *pm8916_get_regmap(struct device *dev) -{ - return dev_get_regmap(dev->parent, NULL); -} - static irqreturn_t mbhc_btn_release_irq_handler(int irq, void *arg) { struct pm8916_wcd_analog_priv *priv = arg; @@ -1082,7 +1079,6 @@ static const struct snd_soc_codec_driver pm8916_wcd_analog = { .probe = pm8916_wcd_analog_probe, .remove = pm8916_wcd_analog_remove, .set_jack = pm8916_wcd_analog_set_jack, - .get_regmap = pm8916_get_regmap, .component_driver = { .controls = pm8916_wcd_analog_snd_controls, .num_controls = ARRAY_SIZE(pm8916_wcd_analog_snd_controls), -- cgit v1.2.3 From 4b952275d2e7c6b32671a121ea5303a467bf2a0f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Nov 2017 06:06:44 +0000 Subject: ASoC: use snd_soc_component_init_regmap() on atmel-classd To setup regmap, ALSA SoC has snd_soc_component_init_regmap() and .get_regmap. But these are duplicated feature. This driver is using .get_regmap and set regmap by using dev_get_regmap(), but it is automatically done by snd_soc_component_add_unlocked(). let's remove .get_regmap. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-classd.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 8445edd06737..ebabed69f0e6 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -308,15 +308,9 @@ static int atmel_classd_codec_resume(struct snd_soc_codec *codec) return regcache_sync(dd->regmap); } -static struct regmap *atmel_classd_codec_get_remap(struct device *dev) -{ - return dev_get_regmap(dev, NULL); -} - static struct snd_soc_codec_driver soc_codec_dev_classd = { .probe = atmel_classd_codec_probe, .resume = atmel_classd_codec_resume, - .get_regmap = atmel_classd_codec_get_remap, .component_driver = { .controls = atmel_classd_snd_controls, .num_controls = ARRAY_SIZE(atmel_classd_snd_controls), -- cgit v1.2.3 From 7afa535eb107d587b22ffbbbaaeb4a0b87b94496 Mon Sep 17 00:00:00 2001 From: "Mukunda, Vijendar" Date: Mon, 4 Dec 2017 20:46:24 +0530 Subject: ASoC: amd: added error checks in dma driver added additional error checks in acp dma driver v2: printed error codes for acp init & acp deinit failure cases. Signed-off-by: Vijendar Mukunda Signed-off-by: Mark Brown --- sound/soc/amd/acp-pcm-dma.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index b5e41df6bb3a..c33a512283a4 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -850,6 +850,9 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct audio_substream_data *rtd = runtime->private_data; + if (!rtd) + return -EINVAL; + buffersize = frames_to_bytes(runtime, runtime->buffer_size); bytescount = acp_get_byte_count(rtd->acp_mmio, substream->stream); @@ -875,6 +878,8 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct audio_substream_data *rtd = runtime->private_data; + if (!rtd) + return -EINVAL; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM, PLAYBACK_START_DMA_DESCR_CH12, @@ -1091,7 +1096,11 @@ static int acp_audio_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, audio_drv_data); /* Initialize the ACP */ - acp_init(audio_drv_data->acp_mmio, audio_drv_data->asic_type); + status = acp_init(audio_drv_data->acp_mmio, audio_drv_data->asic_type); + if (status) { + dev_err(&pdev->dev, "ACP Init failed status:%d\n", status); + return status; + } status = snd_soc_register_platform(&pdev->dev, &acp_asoc_platform); if (status != 0) { @@ -1108,9 +1117,12 @@ static int acp_audio_probe(struct platform_device *pdev) static int acp_audio_remove(struct platform_device *pdev) { + int status; struct audio_drv_data *adata = dev_get_drvdata(&pdev->dev); - acp_deinit(adata->acp_mmio); + status = acp_deinit(adata->acp_mmio); + if (status) + dev_err(&pdev->dev, "ACP Deinit failed status:%d\n", status); snd_soc_unregister_platform(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -1120,9 +1132,14 @@ static int acp_audio_remove(struct platform_device *pdev) static int acp_pcm_resume(struct device *dev) { u16 bank; + int status; struct audio_drv_data *adata = dev_get_drvdata(dev); - acp_init(adata->acp_mmio, adata->asic_type); + status = acp_init(adata->acp_mmio, adata->asic_type); + if (status) { + dev_err(dev, "ACP Init failed status:%d\n", status); + return status; + } if (adata->play_stream && adata->play_stream->runtime) { /* For Stoney, Memory gating is disabled,i.e SRAM Banks @@ -1154,18 +1171,26 @@ static int acp_pcm_resume(struct device *dev) static int acp_pcm_runtime_suspend(struct device *dev) { + int status; struct audio_drv_data *adata = dev_get_drvdata(dev); - acp_deinit(adata->acp_mmio); + status = acp_deinit(adata->acp_mmio); + if (status) + dev_err(dev, "ACP Deinit failed status:%d\n", status); acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); return 0; } static int acp_pcm_runtime_resume(struct device *dev) { + int status; struct audio_drv_data *adata = dev_get_drvdata(dev); - acp_init(adata->acp_mmio, adata->asic_type); + status = acp_init(adata->acp_mmio, adata->asic_type); + if (status) { + dev_err(dev, "ACP Init failed status:%d\n", status); + return status; + } acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); return 0; } -- cgit v1.2.3 From 8e79ec98e1f613f6fda5d91b16f5e38cf0bd4627 Mon Sep 17 00:00:00 2001 From: Guneshwor Singh Date: Mon, 4 Dec 2017 10:30:11 +0530 Subject: ASoC: Intel: Skylake: Make local functions static Some functions are local to the source and do not need to be in global scope, so make them static. Signed-off-by: Guneshwor Singh Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-nhlt.c | 4 ++-- sound/soc/intel/skylake/skl.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 4d2136c0389a..ca5dc2be7b68 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -269,7 +269,7 @@ void skl_nhlt_remove_sysfs(struct skl *skl) * stores all possible rates supported in a rate table for the corresponding * sclk/sclkfs. */ -void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, +static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, struct nhlt_fmt *fmt, u8 id) { struct skl_i2s_config_blob_legacy *i2s_config; @@ -360,7 +360,7 @@ void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, } } -void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk, +static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk, struct nhlt_fmt *fmt, u8 id) { struct skl_i2s_config_blob_legacy *i2s_config; diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 63e5456ef401..a89592b2850e 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -545,7 +545,7 @@ struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id) return NULL; } -void init_skl_xtal_rate(int pci_id) +static void init_skl_xtal_rate(int pci_id) { switch (pci_id) { case 0x9d70: -- cgit v1.2.3 From 446c4724cc7174429ce381e5948e58da07274944 Mon Sep 17 00:00:00 2001 From: Guneshwor Singh Date: Mon, 4 Dec 2017 10:30:12 +0530 Subject: ASoC: Intel: Skylake: Fix descriptions for exported function args Fix a few incorrect descriptions for arguments in exported functions. Signed-off-by: Guneshwor Singh Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-utils.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c index 369ef7ce981c..746df24bfd82 100644 --- a/sound/soc/intel/skylake/skl-sst-utils.c +++ b/sound/soc/intel/skylake/skl-sst-utils.c @@ -178,7 +178,8 @@ static inline int skl_pvtid_128(struct uuid_module *module) * skl_get_pvt_id: generate a private id for use as module id * * @ctx: driver context - * @mconfig: module configuration data + * @uuid_mod: module's uuid + * @instance_id: module's instance id * * This generates a 128 bit private unique id for a module TYPE so that * module instance is unique @@ -208,7 +209,8 @@ EXPORT_SYMBOL_GPL(skl_get_pvt_id); * skl_put_pvt_id: free up the private id allocated * * @ctx: driver context - * @mconfig: module configuration data + * @uuid_mod: module's uuid + * @pvt_id: module pvt id * * This frees a 128 bit private unique id previously generated */ -- cgit v1.2.3 From 8f1a1df58e011e54ffcc2acd09249579e9467544 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Fri, 1 Dec 2017 22:32:35 -0800 Subject: ASoC: eukrea-tlv320: Remove include line of fsl_ssi.h The machine driver links both imx-ssi (legacy non-DT driver) and fsl_ssi (up-to-date DT based driver). So It also includes both imx-ssi.h and fsl_ssi.h header files. This creates a limitation for two header files -- they can't define anything with identical names. Since the eukrea-tlv320 machine driver now does not really need anything being defined in the fsl_ssi header file, and it's also going to take some time to clean up two SSI drivers, this patch takes a quick way to remove the #include fsl_ssi.h line for now. It can be added back once the header files are done refactoring. The eukrea-tlv320 driver is still compiled successfully without any erorr using imx_v6_v7_defconfig, after removing it. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/eukrea-tlv320.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index 84ef6385736c..191426a6d9ad 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c @@ -29,7 +29,6 @@ #include "../codecs/tlv320aic23.h" #include "imx-ssi.h" -#include "fsl_ssi.h" #include "imx-audmux.h" #define CODEC_CLOCK 12000000 -- cgit v1.2.3 From 70424d8e6e15abd32e189130be220d0063e082bc Mon Sep 17 00:00:00 2001 From: John Hsu Date: Fri, 1 Dec 2017 10:01:50 +0800 Subject: ASoC: nau8825: improve semaphore control After reviewing the crosstalk protection, there are two flaws at semaphore control. The first one is that the semaphore releases are not enough; and the other is that down_interruptible has an risk to make the ISR sleep. Therefore, the driver add more releases before the funcitons return. Take down_trylock to replace down_interruptible. The ISR can control the protection as well and never sleep by semaphore. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 603cd72c2a25..5778eadbf9e6 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -245,13 +245,14 @@ static const unsigned short logtable[256] = { * tasks are allowed to acquire the semaphore, calling this function will * put the task to sleep. If the semaphore is not released within the * specified number of jiffies, this function returns. - * Acquires the semaphore without jiffies. If no more tasks are allowed - * to acquire the semaphore, calling this function will put the task to - * sleep until the semaphore is released. * If the semaphore is not released within the specified number of jiffies, - * this function returns -ETIME. - * If the sleep is interrupted by a signal, this function will return -EINTR. - * It returns 0 if the semaphore was acquired successfully. + * this function returns -ETIME. If the sleep is interrupted by a signal, + * this function will return -EINTR. It returns 0 if the semaphore was + * acquired successfully. + * + * Acquires the semaphore without jiffies. Try to acquire the semaphore + * atomically. Returns 0 if the semaphore has been acquired successfully + * or 1 if it it cannot be acquired. */ static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout) { @@ -262,8 +263,8 @@ static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout) if (ret < 0) dev_warn(nau8825->dev, "Acquire semaphore timeout\n"); } else { - ret = down_interruptible(&nau8825->xtalk_sem); - if (ret < 0) + ret = down_trylock(&nau8825->xtalk_sem); + if (ret) dev_warn(nau8825->dev, "Acquire semaphore fail\n"); } @@ -1246,8 +1247,10 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, regmap_read(nau8825->regmap, NAU8825_REG_DAC_CTRL1, &osr); osr &= NAU8825_DAC_OVERSAMPLE_MASK; if (nau8825_clock_check(nau8825, substream->stream, - params_rate(params), osr)) + params_rate(params), osr)) { + nau8825_sema_release(nau8825); return -EINVAL; + } regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, NAU8825_CLK_DAC_SRC_MASK, osr_dac_sel[osr].clk_src << NAU8825_CLK_DAC_SRC_SFT); @@ -1255,8 +1258,10 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, regmap_read(nau8825->regmap, NAU8825_REG_ADC_RATE, &osr); osr &= NAU8825_ADC_SYNC_DOWN_MASK; if (nau8825_clock_check(nau8825, substream->stream, - params_rate(params), osr)) + params_rate(params), osr)) { + nau8825_sema_release(nau8825); return -EINVAL; + } regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, NAU8825_CLK_ADC_SRC_MASK, osr_adc_sel[osr].clk_src << NAU8825_CLK_ADC_SRC_SFT); @@ -1273,8 +1278,10 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, bclk_div = 1; else if (bclk_fs <= 128) bclk_div = 0; - else + else { + nau8825_sema_release(nau8825); return -EINVAL; + } regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, NAU8825_I2S_LRC_DIV_MASK | NAU8825_I2S_BLK_DIV_MASK, ((bclk_div + 1) << NAU8825_I2S_LRC_DIV_SFT) | bclk_div); @@ -1294,6 +1301,7 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, val_len |= NAU8825_I2S_DL_32; break; default: + nau8825_sema_release(nau8825); return -EINVAL; } @@ -1312,8 +1320,6 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); unsigned int ctrl1_val = 0, ctrl2_val = 0; - nau8825_sema_acquire(nau8825, 3 * HZ); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: ctrl2_val |= NAU8825_I2S_MS_MASTER; @@ -1355,6 +1361,8 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } + nau8825_sema_acquire(nau8825, 3 * HZ); + regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1, NAU8825_I2S_DL_MASK | NAU8825_I2S_DF_MASK | NAU8825_I2S_BP_MASK | NAU8825_I2S_PCMB_MASK, @@ -1701,7 +1709,7 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) int ret; nau8825->xtalk_protect = true; ret = nau8825_sema_acquire(nau8825, 0); - if (ret < 0) + if (ret) nau8825->xtalk_protect = false; } /* Startup cross talk detection process */ @@ -2383,7 +2391,7 @@ static int __maybe_unused nau8825_resume(struct snd_soc_codec *codec) regcache_sync(nau8825->regmap); nau8825->xtalk_protect = true; ret = nau8825_sema_acquire(nau8825, 0); - if (ret < 0) + if (ret) nau8825->xtalk_protect = false; enable_irq(nau8825->irq); -- cgit v1.2.3 From fa25b4f59f1de9536104b632ec4c4c0b8f8e54ec Mon Sep 17 00:00:00 2001 From: John Hsu Date: Fri, 1 Dec 2017 10:01:37 +0800 Subject: ASoC: nau8825: improve crosstalk measurement protection The sequence of crosstalk measurement is not robust. The driver add more protections to make it stronger. The improvements as follows: (1)Give backup table the default value. The values are the same with the default of hardware registers. The impact will decline once restoring the backup table in the wrong way. (2)Add xtalk_baktab_initialized flag. The flag can keep the initiation status of backup table. It helps to backup and restore the backup-table correctly. (3)Add cancel parameter in the restore function. The volume ramping should do in crosstalk DONE state only. Otherwise, the delay action is not allowed because the restore may happen during the jack eject interruption. (4)Add xtalk_protect condition check before scheduling work in ISR. It makes sure the semaphore hold during the crosstalk measurement. The sequence is still under protection from playback interference. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 45 +++++++++++++++++++++++++++++++-------------- sound/soc/codecs/nau8825.h | 1 + 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 5778eadbf9e6..2aea642b4a5d 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -194,10 +194,10 @@ static const struct reg_default nau8825_reg_defaults[] = { /* register backup table when cross talk detection */ static struct reg_default nau8825_xtalk_baktab[] = { - { NAU8825_REG_ADC_DGAIN_CTRL, 0 }, + { NAU8825_REG_ADC_DGAIN_CTRL, 0x00cf }, { NAU8825_REG_HSVOL_CTRL, 0 }, - { NAU8825_REG_DACL_CTRL, 0 }, - { NAU8825_REG_DACR_CTRL, 0 }, + { NAU8825_REG_DACL_CTRL, 0x00cf }, + { NAU8825_REG_DACR_CTRL, 0x02cf }, }; static const unsigned short logtable[256] = { @@ -455,22 +455,32 @@ static void nau8825_xtalk_backup(struct nau8825 *nau8825) { int i; + if (nau8825->xtalk_baktab_initialized) + return; + /* Backup some register values to backup table */ for (i = 0; i < ARRAY_SIZE(nau8825_xtalk_baktab); i++) regmap_read(nau8825->regmap, nau8825_xtalk_baktab[i].reg, &nau8825_xtalk_baktab[i].def); + + nau8825->xtalk_baktab_initialized = true; } -static void nau8825_xtalk_restore(struct nau8825 *nau8825) +static void nau8825_xtalk_restore(struct nau8825 *nau8825, bool cause_cancel) { int i, volume; + if (!nau8825->xtalk_baktab_initialized) + return; + /* Restore register values from backup table; When the driver restores - * the headphone volumem, it needs recover to original level gradually - * with 3dB per step for less pop noise. + * the headphone volume in XTALK_DONE state, it needs recover to + * original level gradually with 3dB per step for less pop noise. + * Otherwise, the restore should do ASAP. */ for (i = 0; i < ARRAY_SIZE(nau8825_xtalk_baktab); i++) { - if (nau8825_xtalk_baktab[i].reg == NAU8825_REG_HSVOL_CTRL) { + if (!cause_cancel && nau8825_xtalk_baktab[i].reg == + NAU8825_REG_HSVOL_CTRL) { /* Ramping up the volume change to reduce pop noise */ volume = nau8825_xtalk_baktab[i].def & NAU8825_HPR_VOL_MASK; @@ -480,6 +490,8 @@ static void nau8825_xtalk_restore(struct nau8825 *nau8825) regmap_write(nau8825->regmap, nau8825_xtalk_baktab[i].reg, nau8825_xtalk_baktab[i].def); } + + nau8825->xtalk_baktab_initialized = false; } static void nau8825_xtalk_prepare_dac(struct nau8825 *nau8825) @@ -645,7 +657,7 @@ static void nau8825_xtalk_clean_adc(struct nau8825 *nau8825) NAU8825_POWERUP_ADCL | NAU8825_ADC_VREFSEL_MASK, 0); } -static void nau8825_xtalk_clean(struct nau8825 *nau8825) +static void nau8825_xtalk_clean(struct nau8825 *nau8825, bool cause_cancel) { /* Enable internal VCO needed for interruptions */ nau8825_configure_sysclk(nau8825, NAU8825_CLK_INTERNAL, 0); @@ -661,7 +673,7 @@ static void nau8825_xtalk_clean(struct nau8825 *nau8825) NAU8825_I2S_MS_MASK | NAU8825_I2S_LRC_DIV_MASK | NAU8825_I2S_BLK_DIV_MASK, NAU8825_I2S_MS_SLAVE); /* Restore value of specific register for cross talk */ - nau8825_xtalk_restore(nau8825); + nau8825_xtalk_restore(nau8825, cause_cancel); } static void nau8825_xtalk_imm_start(struct nau8825 *nau8825, int vol) @@ -780,7 +792,7 @@ static void nau8825_xtalk_measure(struct nau8825 *nau8825) dev_dbg(nau8825->dev, "cross talk sidetone: %x\n", sidetone); regmap_write(nau8825->regmap, NAU8825_REG_DAC_DGAIN_CTRL, (sidetone << 8) | sidetone); - nau8825_xtalk_clean(nau8825); + nau8825_xtalk_clean(nau8825, false); nau8825->xtalk_state = NAU8825_XTALK_DONE; break; default: @@ -823,7 +835,7 @@ static void nau8825_xtalk_cancel(struct nau8825 *nau8825) if (nau8825->xtalk_enable && nau8825->xtalk_state != NAU8825_XTALK_DONE) { cancel_work_sync(&nau8825->xtalk_work); - nau8825_xtalk_clean(nau8825); + nau8825_xtalk_clean(nau8825, true); } /* Reset parameters for cross talk suppression function */ nau8825_sema_reset(nau8825); @@ -1713,8 +1725,11 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) nau8825->xtalk_protect = false; } /* Startup cross talk detection process */ - nau8825->xtalk_state = NAU8825_XTALK_PREPARE; - schedule_work(&nau8825->xtalk_work); + if (nau8825->xtalk_protect) { + nau8825->xtalk_state = + NAU8825_XTALK_PREPARE; + schedule_work(&nau8825->xtalk_work); + } } else { /* The cross talk suppression shouldn't apply * in the headset with high impedance. Thus, @@ -1741,7 +1756,8 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) nau8825->xtalk_event_mask = event_mask; } } else if (active_irq & NAU8825_IMPEDANCE_MEAS_IRQ) { - if (nau8825->xtalk_enable) + /* crosstalk detection enable and process on going */ + if (nau8825->xtalk_enable && nau8825->xtalk_protect) schedule_work(&nau8825->xtalk_work); clear_irq = NAU8825_IMPEDANCE_MEAS_IRQ; } else if ((active_irq & NAU8825_JACK_INSERTION_IRQ_MASK) == @@ -2578,6 +2594,7 @@ static int nau8825_i2c_probe(struct i2c_client *i2c, */ nau8825->xtalk_state = NAU8825_XTALK_DONE; nau8825->xtalk_protect = false; + nau8825->xtalk_baktab_initialized = false; sema_init(&nau8825->xtalk_sem, 1); INIT_WORK(&nau8825->xtalk_work, nau8825_xtalk_work); diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 199d6ea4dcdc..f7e732125882 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -477,6 +477,7 @@ struct nau8825 { bool xtalk_protect; int imp_rms[NAU8825_XTALK_IMM]; int xtalk_enable; + bool xtalk_baktab_initialized; /* True if initialized. */ }; int nau8825_enable_jack_detect(struct snd_soc_codec *codec, -- cgit v1.2.3 From eb733366f5f7f416a7d9215a40e00d57aa193361 Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Wed, 22 Nov 2017 20:43:14 +0900 Subject: ASoC: spdif: Add S32_LE support for S/PDIF dummy codec drivers AIO on UniPhier can output S/PDIF where no codec is needed. This patch adds S32_LE support for dummy codec drivers. If one S/PDIF controller has its own limitation, its CPU DAI driver should set the supported format by its own circumstance, since the soc-pcm driver will use the intersection of cpu_dai's formats and codec_dai's formats. Signed-off-by: Katsuhiro Suzuki Signed-off-by: Mark Brown --- sound/soc/codecs/spdif_receiver.c | 5 +++-- sound/soc/codecs/spdif_transmitter.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c index 7acd05140a81..c8fd6367f6c0 100644 --- a/sound/soc/codecs/spdif_receiver.c +++ b/sound/soc/codecs/spdif_receiver.c @@ -34,10 +34,11 @@ static const struct snd_soc_dapm_route dir_routes[] = { #define STUB_RATES SNDRV_PCM_RATE_8000_192000 #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S20_3LE | \ - SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE | \ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) -static const struct snd_soc_codec_driver soc_codec_spdif_dir = { +static struct snd_soc_codec_driver soc_codec_spdif_dir = { .component_driver = { .dapm_widgets = dir_widgets, .num_dapm_widgets = ARRAY_SIZE(dir_widgets), diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c index 063a64ff82d3..037aa1d45559 100644 --- a/sound/soc/codecs/spdif_transmitter.c +++ b/sound/soc/codecs/spdif_transmitter.c @@ -27,7 +27,8 @@ #define STUB_RATES SNDRV_PCM_RATE_8000_192000 #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S20_3LE | \ - SNDRV_PCM_FMTBIT_S24_LE) + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dapm_widget dit_widgets[] = { SND_SOC_DAPM_OUTPUT("spdif-out"), @@ -37,7 +38,7 @@ static const struct snd_soc_dapm_route dit_routes[] = { { "spdif-out", NULL, "Playback" }, }; -static const struct snd_soc_codec_driver soc_codec_spdif_dit = { +static struct snd_soc_codec_driver soc_codec_spdif_dit = { .component_driver = { .dapm_widgets = dit_widgets, .num_dapm_widgets = ARRAY_SIZE(dit_widgets), -- cgit v1.2.3 From e85c8d3e25c09fd9b21ba74e14078ab4c1d977ef Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Wed, 22 Nov 2017 20:43:15 +0900 Subject: ASoC: uniphier: add DT bindings documentation for UniPhier EVEA This patch adds DT binding documentation for UniPhier EVEA that is SoC inner sound codec of UniPhier series. Signed-off-by: Katsuhiro Suzuki Acked-by: Rob Herring Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/uniphier,evea.txt | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/uniphier,evea.txt diff --git a/Documentation/devicetree/bindings/sound/uniphier,evea.txt b/Documentation/devicetree/bindings/sound/uniphier,evea.txt new file mode 100644 index 000000000000..3f31b235f18b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/uniphier,evea.txt @@ -0,0 +1,26 @@ +Socionext EVEA - UniPhier SoC internal codec driver + +Required properties: +- compatible : should be "socionext,uniphier-evea". +- reg : offset and length of the register set for the device. +- clock-names : should include following entries: + "evea", "exiv" +- clocks : a list of phandle, should contain an entry for each + entries in clock-names. +- reset-names : should include following entries: + "evea", "exiv", "adamv" +- resets : a list of phandle, should contain reset entries of + reset-names. +- #sound-dai-cells: should be 1. + +Example: + + codec { + compatible = "socionext,uniphier-evea"; + reg = <0x57900000 0x1000>; + clock-names = "evea", "exiv"; + clocks = <&sys_clk 41>, <&sys_clk 42>; + reset-names = "evea", "exiv", "adamv"; + resets = <&sys_rst 41>, <&sys_rst 42>, <&adamv_rst 0>; + #sound-dai-cells = <1>; + }; -- cgit v1.2.3 From 3a47b1dfa2913038623cec3164adfb2448269fa6 Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Wed, 22 Nov 2017 20:43:17 +0900 Subject: ASoC: uniphier: add support for UniPhier EVEA codec This patch adds EVEA codec driver. This codec core is in inside of UniPhier SoC. Signed-off-by: Katsuhiro Suzuki Signed-off-by: Mark Brown --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/uniphier/Kconfig | 19 ++ sound/soc/uniphier/Makefile | 3 + sound/soc/uniphier/evea.c | 567 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 591 insertions(+) create mode 100644 sound/soc/uniphier/Kconfig create mode 100644 sound/soc/uniphier/Makefile create mode 100644 sound/soc/uniphier/evea.c diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index d22758165496..84c3582f3982 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -71,6 +71,7 @@ source "sound/soc/stm/Kconfig" source "sound/soc/sunxi/Kconfig" source "sound/soc/tegra/Kconfig" source "sound/soc/txx9/Kconfig" +source "sound/soc/uniphier/Kconfig" source "sound/soc/ux500/Kconfig" source "sound/soc/xtensa/Kconfig" source "sound/soc/zte/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 5327f4d6c668..74cd1858d38b 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_SND_SOC) += stm/ obj-$(CONFIG_SND_SOC) += sunxi/ obj-$(CONFIG_SND_SOC) += tegra/ obj-$(CONFIG_SND_SOC) += txx9/ +obj-$(CONFIG_SND_SOC) += uniphier/ obj-$(CONFIG_SND_SOC) += ux500/ obj-$(CONFIG_SND_SOC) += xtensa/ obj-$(CONFIG_SND_SOC) += zte/ diff --git a/sound/soc/uniphier/Kconfig b/sound/soc/uniphier/Kconfig new file mode 100644 index 000000000000..02886a457eaf --- /dev/null +++ b/sound/soc/uniphier/Kconfig @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0 +config SND_SOC_UNIPHIER + tristate "ASoC support for UniPhier" + depends on (ARCH_UNIPHIER || COMPILE_TEST) + help + Say Y or M if you want to add support for the Socionext + UniPhier SoC audio interfaces. You will also need to select the + audio interfaces to support below. + If unsure select "N". + +config SND_SOC_UNIPHIER_EVEA_CODEC + tristate "UniPhier SoC internal audio codec" + depends on SND_SOC_UNIPHIER + select REGMAP_MMIO + help + This adds Codec driver for Socionext UniPhier LD11/20 SoC + internal DAC. This driver supports Line In / Out and HeadPhone. + Select Y if you use such device. + If unsure select "N". diff --git a/sound/soc/uniphier/Makefile b/sound/soc/uniphier/Makefile new file mode 100644 index 000000000000..3be00d72f5e5 --- /dev/null +++ b/sound/soc/uniphier/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +snd-soc-uniphier-evea-objs := evea.o +obj-$(CONFIG_SND_SOC_UNIPHIER_EVEA_CODEC) += snd-soc-uniphier-evea.o diff --git a/sound/soc/uniphier/evea.c b/sound/soc/uniphier/evea.c new file mode 100644 index 000000000000..0cc9efff1d9a --- /dev/null +++ b/sound/soc/uniphier/evea.c @@ -0,0 +1,567 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Socionext UniPhier EVEA ADC/DAC codec driver. + * + * Copyright (c) 2016-2017 Socionext Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "evea" +#define EVEA_RATES SNDRV_PCM_RATE_48000 +#define EVEA_FORMATS SNDRV_PCM_FMTBIT_S32_LE + +#define AADCPOW(n) (0x0078 + 0x04 * (n)) +#define AADCPOW_AADC_POWD BIT(0) +#define AHPOUTPOW 0x0098 +#define AHPOUTPOW_HP_ON BIT(4) +#define ALINEPOW 0x009c +#define ALINEPOW_LIN2_POWD BIT(3) +#define ALINEPOW_LIN1_POWD BIT(4) +#define ALO1OUTPOW 0x00a8 +#define ALO1OUTPOW_LO1_ON BIT(4) +#define ALO2OUTPOW 0x00ac +#define ALO2OUTPOW_ADAC2_MUTE BIT(0) +#define ALO2OUTPOW_LO2_ON BIT(4) +#define AANAPOW 0x00b8 +#define AANAPOW_A_POWD BIT(4) +#define ADACSEQ1(n) (0x0144 + 0x40 * (n)) +#define ADACSEQ1_MMUTE BIT(1) +#define ADACSEQ2(n) (0x0160 + 0x40 * (n)) +#define ADACSEQ2_ADACIN_FIX BIT(0) +#define ADAC1ODC 0x0200 +#define ADAC1ODC_HP_DIS_RES_MASK GENMASK(2, 1) +#define ADAC1ODC_HP_DIS_RES_OFF (0x0 << 1) +#define ADAC1ODC_HP_DIS_RES_ON (0x3 << 1) +#define ADAC1ODC_ADAC_RAMPCLT_MASK GENMASK(8, 7) +#define ADAC1ODC_ADAC_RAMPCLT_NORMAL (0x0 << 7) +#define ADAC1ODC_ADAC_RAMPCLT_REDUCE (0x1 << 7) + +struct evea_priv { + struct clk *clk, *clk_exiv; + struct reset_control *rst, *rst_exiv, *rst_adamv; + struct regmap *regmap; + + int switch_lin; + int switch_lo; + int switch_hp; +}; + +static const struct snd_soc_dapm_widget evea_widgets[] = { + SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_INPUT("LIN1_LP"), + SND_SOC_DAPM_INPUT("LIN1_RP"), + SND_SOC_DAPM_INPUT("LIN2_LP"), + SND_SOC_DAPM_INPUT("LIN2_RP"), + SND_SOC_DAPM_INPUT("LIN3_LP"), + SND_SOC_DAPM_INPUT("LIN3_RP"), + + SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("HP1_L"), + SND_SOC_DAPM_OUTPUT("HP1_R"), + SND_SOC_DAPM_OUTPUT("LO2_L"), + SND_SOC_DAPM_OUTPUT("LO2_R"), +}; + +static const struct snd_soc_dapm_route evea_routes[] = { + { "ADC", NULL, "LIN1_LP" }, + { "ADC", NULL, "LIN1_RP" }, + { "ADC", NULL, "LIN2_LP" }, + { "ADC", NULL, "LIN2_RP" }, + { "ADC", NULL, "LIN3_LP" }, + { "ADC", NULL, "LIN3_RP" }, + + { "HP1_L", NULL, "DAC" }, + { "HP1_R", NULL, "DAC" }, + { "LO2_L", NULL, "DAC" }, + { "LO2_R", NULL, "DAC" }, +}; + +static void evea_set_power_state_on(struct evea_priv *evea) +{ + struct regmap *map = evea->regmap; + + regmap_update_bits(map, AANAPOW, AANAPOW_A_POWD, + AANAPOW_A_POWD); + + regmap_update_bits(map, ADAC1ODC, ADAC1ODC_HP_DIS_RES_MASK, + ADAC1ODC_HP_DIS_RES_ON); + + regmap_update_bits(map, ADAC1ODC, ADAC1ODC_ADAC_RAMPCLT_MASK, + ADAC1ODC_ADAC_RAMPCLT_REDUCE); + + regmap_update_bits(map, ADACSEQ2(0), ADACSEQ2_ADACIN_FIX, 0); + regmap_update_bits(map, ADACSEQ2(1), ADACSEQ2_ADACIN_FIX, 0); + regmap_update_bits(map, ADACSEQ2(2), ADACSEQ2_ADACIN_FIX, 0); +} + +static void evea_set_power_state_off(struct evea_priv *evea) +{ + struct regmap *map = evea->regmap; + + regmap_update_bits(map, ADAC1ODC, ADAC1ODC_HP_DIS_RES_MASK, + ADAC1ODC_HP_DIS_RES_ON); + + regmap_update_bits(map, ADACSEQ1(0), ADACSEQ1_MMUTE, + ADACSEQ1_MMUTE); + regmap_update_bits(map, ADACSEQ1(1), ADACSEQ1_MMUTE, + ADACSEQ1_MMUTE); + regmap_update_bits(map, ADACSEQ1(2), ADACSEQ1_MMUTE, + ADACSEQ1_MMUTE); + + regmap_update_bits(map, ALO1OUTPOW, ALO1OUTPOW_LO1_ON, 0); + regmap_update_bits(map, ALO2OUTPOW, ALO2OUTPOW_LO2_ON, 0); + regmap_update_bits(map, AHPOUTPOW, AHPOUTPOW_HP_ON, 0); +} + +static int evea_update_switch_lin(struct evea_priv *evea) +{ + struct regmap *map = evea->regmap; + + if (evea->switch_lin) { + regmap_update_bits(map, ALINEPOW, + ALINEPOW_LIN2_POWD | ALINEPOW_LIN1_POWD, + ALINEPOW_LIN2_POWD | ALINEPOW_LIN1_POWD); + + regmap_update_bits(map, AADCPOW(0), AADCPOW_AADC_POWD, + AADCPOW_AADC_POWD); + regmap_update_bits(map, AADCPOW(1), AADCPOW_AADC_POWD, + AADCPOW_AADC_POWD); + } else { + regmap_update_bits(map, AADCPOW(0), AADCPOW_AADC_POWD, 0); + regmap_update_bits(map, AADCPOW(1), AADCPOW_AADC_POWD, 0); + + regmap_update_bits(map, ALINEPOW, + ALINEPOW_LIN2_POWD | ALINEPOW_LIN1_POWD, 0); + } + + return 0; +} + +static int evea_update_switch_lo(struct evea_priv *evea) +{ + struct regmap *map = evea->regmap; + + if (evea->switch_lo) { + regmap_update_bits(map, ADACSEQ1(0), ADACSEQ1_MMUTE, 0); + regmap_update_bits(map, ADACSEQ1(2), ADACSEQ1_MMUTE, 0); + + regmap_update_bits(map, ALO1OUTPOW, ALO1OUTPOW_LO1_ON, + ALO1OUTPOW_LO1_ON); + regmap_update_bits(map, ALO2OUTPOW, + ALO2OUTPOW_ADAC2_MUTE | ALO2OUTPOW_LO2_ON, + ALO2OUTPOW_ADAC2_MUTE | ALO2OUTPOW_LO2_ON); + } else { + regmap_update_bits(map, ADACSEQ1(0), ADACSEQ1_MMUTE, + ADACSEQ1_MMUTE); + regmap_update_bits(map, ADACSEQ1(2), ADACSEQ1_MMUTE, + ADACSEQ1_MMUTE); + + regmap_update_bits(map, ALO1OUTPOW, ALO1OUTPOW_LO1_ON, 0); + regmap_update_bits(map, ALO2OUTPOW, + ALO2OUTPOW_ADAC2_MUTE | ALO2OUTPOW_LO2_ON, + 0); + } + + return 0; +} + +static int evea_update_switch_hp(struct evea_priv *evea) +{ + struct regmap *map = evea->regmap; + + if (evea->switch_hp) { + regmap_update_bits(map, ADACSEQ1(1), ADACSEQ1_MMUTE, 0); + + regmap_update_bits(map, AHPOUTPOW, AHPOUTPOW_HP_ON, + AHPOUTPOW_HP_ON); + + regmap_update_bits(map, ADAC1ODC, ADAC1ODC_HP_DIS_RES_MASK, + ADAC1ODC_HP_DIS_RES_OFF); + } else { + regmap_update_bits(map, ADAC1ODC, ADAC1ODC_HP_DIS_RES_MASK, + ADAC1ODC_HP_DIS_RES_ON); + + regmap_update_bits(map, ADACSEQ1(1), ADACSEQ1_MMUTE, + ADACSEQ1_MMUTE); + + regmap_update_bits(map, AHPOUTPOW, AHPOUTPOW_HP_ON, 0); + } + + return 0; +} + +static void evea_update_switch_all(struct evea_priv *evea) +{ + evea_update_switch_lin(evea); + evea_update_switch_lo(evea); + evea_update_switch_hp(evea); +} + +static int evea_get_switch_lin(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct evea_priv *evea = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = evea->switch_lin; + + return 0; +} + +static int evea_set_switch_lin(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct evea_priv *evea = snd_soc_codec_get_drvdata(codec); + + if (evea->switch_lin == ucontrol->value.integer.value[0]) + return 0; + + evea->switch_lin = ucontrol->value.integer.value[0]; + + return evea_update_switch_lin(evea); +} + +static int evea_get_switch_lo(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct evea_priv *evea = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = evea->switch_lo; + + return 0; +} + +static int evea_set_switch_lo(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct evea_priv *evea = snd_soc_codec_get_drvdata(codec); + + if (evea->switch_lo == ucontrol->value.integer.value[0]) + return 0; + + evea->switch_lo = ucontrol->value.integer.value[0]; + + return evea_update_switch_lo(evea); +} + +static int evea_get_switch_hp(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct evea_priv *evea = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = evea->switch_hp; + + return 0; +} + +static int evea_set_switch_hp(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct evea_priv *evea = snd_soc_codec_get_drvdata(codec); + + if (evea->switch_hp == ucontrol->value.integer.value[0]) + return 0; + + evea->switch_hp = ucontrol->value.integer.value[0]; + + return evea_update_switch_hp(evea); +} + +static const struct snd_kcontrol_new eva_controls[] = { + SOC_SINGLE_BOOL_EXT("Line Capture Switch", 0, + evea_get_switch_lin, evea_set_switch_lin), + SOC_SINGLE_BOOL_EXT("Line Playback Switch", 0, + evea_get_switch_lo, evea_set_switch_lo), + SOC_SINGLE_BOOL_EXT("Headphone Playback Switch", 0, + evea_get_switch_hp, evea_set_switch_hp), +}; + +static int evea_codec_probe(struct snd_soc_codec *codec) +{ + struct evea_priv *evea = snd_soc_codec_get_drvdata(codec); + + evea->switch_lin = 1; + evea->switch_lo = 1; + evea->switch_hp = 1; + + evea_set_power_state_on(evea); + evea_update_switch_all(evea); + + return 0; +} + +static int evea_codec_suspend(struct snd_soc_codec *codec) +{ + struct evea_priv *evea = snd_soc_codec_get_drvdata(codec); + + evea_set_power_state_off(evea); + + reset_control_assert(evea->rst_adamv); + reset_control_assert(evea->rst_exiv); + reset_control_assert(evea->rst); + + clk_disable_unprepare(evea->clk_exiv); + clk_disable_unprepare(evea->clk); + + return 0; +} + +static int evea_codec_resume(struct snd_soc_codec *codec) +{ + struct evea_priv *evea = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = clk_prepare_enable(evea->clk); + if (ret) + return ret; + + ret = clk_prepare_enable(evea->clk_exiv); + if (ret) + goto err_out_clock; + + ret = reset_control_deassert(evea->rst); + if (ret) + goto err_out_clock_exiv; + + ret = reset_control_deassert(evea->rst_exiv); + if (ret) + goto err_out_reset; + + ret = reset_control_deassert(evea->rst_adamv); + if (ret) + goto err_out_reset_exiv; + + evea_set_power_state_on(evea); + evea_update_switch_all(evea); + + return 0; + +err_out_reset_exiv: + reset_control_assert(evea->rst_exiv); + +err_out_reset: + reset_control_assert(evea->rst); + +err_out_clock_exiv: + clk_disable_unprepare(evea->clk_exiv); + +err_out_clock: + clk_disable_unprepare(evea->clk); + + return ret; +} + +static struct snd_soc_codec_driver soc_codec_evea = { + .probe = evea_codec_probe, + .suspend = evea_codec_suspend, + .resume = evea_codec_resume, + + .component_driver = { + .dapm_widgets = evea_widgets, + .num_dapm_widgets = ARRAY_SIZE(evea_widgets), + .dapm_routes = evea_routes, + .num_dapm_routes = ARRAY_SIZE(evea_routes), + .controls = eva_controls, + .num_controls = ARRAY_SIZE(eva_controls), + }, +}; + +static struct snd_soc_dai_driver soc_dai_evea[] = { + { + .name = DRV_NAME "-line1", + .playback = { + .stream_name = "Line Out 1", + .formats = EVEA_FORMATS, + .rates = EVEA_RATES, + .channels_min = 2, + .channels_max = 2, + }, + .capture = { + .stream_name = "Line In 1", + .formats = EVEA_FORMATS, + .rates = EVEA_RATES, + .channels_min = 2, + .channels_max = 2, + }, + }, + { + .name = DRV_NAME "-hp1", + .playback = { + .stream_name = "Headphone 1", + .formats = EVEA_FORMATS, + .rates = EVEA_RATES, + .channels_min = 2, + .channels_max = 2, + }, + }, + { + .name = DRV_NAME "-lo2", + .playback = { + .stream_name = "Line Out 2", + .formats = EVEA_FORMATS, + .rates = EVEA_RATES, + .channels_min = 2, + .channels_max = 2, + }, + }, +}; + +static const struct regmap_config evea_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xffc, + .cache_type = REGCACHE_NONE, +}; + +static int evea_probe(struct platform_device *pdev) +{ + struct evea_priv *evea; + struct resource *res; + void __iomem *preg; + int ret; + + evea = devm_kzalloc(&pdev->dev, sizeof(struct evea_priv), GFP_KERNEL); + if (!evea) + return -ENOMEM; + + evea->clk = devm_clk_get(&pdev->dev, "evea"); + if (IS_ERR(evea->clk)) + return PTR_ERR(evea->clk); + + evea->clk_exiv = devm_clk_get(&pdev->dev, "exiv"); + if (IS_ERR(evea->clk_exiv)) + return PTR_ERR(evea->clk_exiv); + + evea->rst = devm_reset_control_get_shared(&pdev->dev, "evea"); + if (IS_ERR(evea->rst)) + return PTR_ERR(evea->rst); + + evea->rst_exiv = devm_reset_control_get_shared(&pdev->dev, "exiv"); + if (IS_ERR(evea->rst_exiv)) + return PTR_ERR(evea->rst_exiv); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + preg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(preg)) + return PTR_ERR(preg); + + evea->regmap = devm_regmap_init_mmio(&pdev->dev, preg, + &evea_regmap_config); + if (IS_ERR(evea->regmap)) + return PTR_ERR(evea->regmap); + + ret = clk_prepare_enable(evea->clk); + if (ret) + return ret; + + ret = clk_prepare_enable(evea->clk_exiv); + if (ret) + goto err_out_clock; + + ret = reset_control_deassert(evea->rst); + if (ret) + goto err_out_clock_exiv; + + ret = reset_control_deassert(evea->rst_exiv); + if (ret) + goto err_out_reset; + + /* ADAMV will hangup if EXIV reset is asserted */ + evea->rst_adamv = devm_reset_control_get_shared(&pdev->dev, "adamv"); + if (IS_ERR(evea->rst_adamv)) { + ret = PTR_ERR(evea->rst_adamv); + goto err_out_reset_exiv; + } + + ret = reset_control_deassert(evea->rst_adamv); + if (ret) + goto err_out_reset_exiv; + + platform_set_drvdata(pdev, evea); + + ret = snd_soc_register_codec(&pdev->dev, &soc_codec_evea, + soc_dai_evea, ARRAY_SIZE(soc_dai_evea)); + if (ret) + goto err_out_reset_adamv; + + return 0; + +err_out_reset_adamv: + reset_control_assert(evea->rst_adamv); + +err_out_reset_exiv: + reset_control_assert(evea->rst_exiv); + +err_out_reset: + reset_control_assert(evea->rst); + +err_out_clock_exiv: + clk_disable_unprepare(evea->clk_exiv); + +err_out_clock: + clk_disable_unprepare(evea->clk); + + return ret; +} + +static int evea_remove(struct platform_device *pdev) +{ + struct evea_priv *evea = platform_get_drvdata(pdev); + + snd_soc_unregister_codec(&pdev->dev); + + reset_control_assert(evea->rst_adamv); + reset_control_assert(evea->rst_exiv); + reset_control_assert(evea->rst); + + clk_disable_unprepare(evea->clk_exiv); + clk_disable_unprepare(evea->clk); + + return 0; +} + +static const struct of_device_id evea_of_match[] = { + { .compatible = "socionext,uniphier-evea", }, + {} +}; +MODULE_DEVICE_TABLE(of, evea_of_match); + +static struct platform_driver evea_codec_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = of_match_ptr(evea_of_match), + }, + .probe = evea_probe, + .remove = evea_remove, +}; +module_platform_driver(evea_codec_driver); + +MODULE_AUTHOR("Katsuhiro Suzuki "); +MODULE_DESCRIPTION("UniPhier EVEA codec driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 576f8f46e7c923f830dfa61924ad547447399b05 Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Wed, 22 Nov 2017 20:43:20 +0900 Subject: MAINTAINERS: add entries for UniPhier ASoC sound drivers Signed-off-by: Katsuhiro Suzuki Signed-off-by: Mark Brown --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index aa71ab52fd76..55ae8ea8722a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12581,6 +12581,12 @@ F: include/media/soc* F: drivers/media/i2c/soc_camera/ F: drivers/media/platform/soc_camera/ +SOCIONEXT UNIPHIER SOUND DRIVER +M: Katsuhiro Suzuki +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Maintained +F: sound/soc/uniphier/ + SOEKRIS NET48XX LED SUPPORT M: Chris Boot S: Maintained -- cgit v1.2.3 From 3b6eed8deb37c349bffc7b3b4d722ce4023f8b11 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Dec 2017 04:20:42 +0000 Subject: ASoC: don't use rtd->codec on soc_dev_attr_is_visible() rtd->codec will be removed soon. checking rtd->num_codecs is enough Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c0edac80df34..90f1122d91c4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -213,7 +213,7 @@ static umode_t soc_dev_attr_is_visible(struct kobject *kobj, if (attr == &dev_attr_pmdown_time.attr) return attr->mode; /* always visible */ - return rtd->codec ? attr->mode : 0; /* enabled only with codec */ + return rtd->num_codecs ? attr->mode : 0; /* enabled only with codec */ } static const struct attribute_group soc_dapm_dev_group = { -- cgit v1.2.3 From e5acfc7d3562ae251cb786b5b52d4345dd16a02c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Dec 2017 04:23:05 +0000 Subject: ASoC: don't use rtd->codec on snd_soc_new_compress() rtd->codec will be removed soon. rtd->codec = rtd->codec_dai->codec, thus, we can use rtd->codec_dai->component instead of it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index d9b1e6417fb9..81232f4ab614 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -1096,7 +1096,6 @@ static struct snd_compr_ops soc_compr_dyn_ops = { */ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) { - struct snd_soc_codec *codec = rtd->codec; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; @@ -1199,8 +1198,9 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) ret = snd_compress_new(rtd->card->snd_card, num, direction, new_name, compr); if (ret < 0) { + component = rtd->codec_dai->component; pr_err("compress asoc: can't create compress for codec %s\n", - codec->component.name); + component->name); goto compr_err; } -- cgit v1.2.3 From 845f80cb401c2ff6b9b8d75ebfc04b83b70268ef Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Dec 2017 04:23:21 +0000 Subject: ASoC: don't use rtd->codec on fsl-asoc-card rtd->codec will be removed soon. rtd->codec = rtd->codec_dai->codec, thus, we can use rtd->codec_dai->component instead of it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 1225e0399de8..989be518c4ed 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -442,8 +442,8 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card) if (fsl_asoc_card_is_ac97(priv)) { #if IS_ENABLED(CONFIG_SND_AC97_CODEC) - struct snd_soc_codec *codec = rtd->codec; - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = rtd->codec_dai->component; + struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component); /* * Use slots 3/4 for S/PDIF so SSI won't try to enable -- cgit v1.2.3 From 356a383bd978e58b5324284dc21210467968b4ff Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Dec 2017 04:23:35 +0000 Subject: ASoC: don't use rtd->codec on intel/skylake rtd->codec will be removed soon. rtd->codec = rtd->codec_dai->codec, thus, we can use rtd->codec_dai->component instead of it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 4380e40c6af0..18138dc872d9 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -536,7 +536,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); - link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); + link = snd_hdac_ext_bus_get_link(ebus, codec_dai->component->name); if (!link) return -EINVAL; @@ -619,7 +619,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream, link_dev->link_prepared = 0; - link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); + link = snd_hdac_ext_bus_get_link(ebus, rtd->codec_dai->component->name); if (!link) return -EINVAL; -- cgit v1.2.3 From 187c43df88196c0c4b231771a39e4a46f20a4f7a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Dec 2017 04:23:52 +0000 Subject: ASoC: don't use rtd->codec on Intel/haswell rtd->codec will be removed soon. rtd->codec = rtd->codec_dai->codec, thus, we can use rtd->codec_dai->component instead of it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/intel/boards/haswell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index 5e1ea0371c90..3c5160779204 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -76,7 +76,7 @@ static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream, } /* set correct codec filter for DAI format and clock config */ - snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000); + snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000); return ret; } -- cgit v1.2.3 From 96e1b9eef4e53a1fea2b889881ca293d153fe0d1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Dec 2017 04:24:13 +0000 Subject: ASoC: don't use rtd->codec on qcom/apq8016_sbc rtd->codec will be removed soon. rtd->codec = rtd->codec_dai->codec, thus, we can use rtd->codec_dai->component instead of it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/qcom/apq8016_sbc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index 03851fedd1e2..704428735e3c 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -43,7 +43,7 @@ struct apq8016_sbc_data { static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_codec *codec; + struct snd_soc_component *component; struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_card *card = rtd->card; struct apq8016_sbc_data *pdata = snd_soc_card_get_drvdata(card); @@ -102,15 +102,15 @@ static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) for (i = 0 ; i < dai_link->num_codecs; i++) { struct snd_soc_dai *dai = rtd->codec_dais[i]; - codec = dai->codec; + component = dai->component; /* Set default mclk for internal codec */ - rval = snd_soc_codec_set_sysclk(codec, 0, 0, DEFAULT_MCLK_RATE, + rval = snd_soc_component_set_sysclk(component, 0, 0, DEFAULT_MCLK_RATE, SND_SOC_CLOCK_IN); if (rval != 0 && rval != -ENOTSUPP) { dev_warn(card->dev, "Failed to set mclk: %d\n", rval); return rval; } - rval = snd_soc_codec_set_jack(codec, &pdata->jack, NULL); + rval = snd_soc_component_set_jack(component, &pdata->jack, NULL); if (rval != 0 && rval != -ENOTSUPP) { dev_warn(card->dev, "Failed to set jack: %d\n", rval); return rval; -- cgit v1.2.3 From f4a2be1c559e53e31545bdea2c246dbce6b70e1c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Dec 2017 04:24:28 +0000 Subject: ASoC: don't use rtd->codec on samsung/bells rtd->codec will be removed soon. rtd->codec = rtd->codec_dai->codec, thus, we can use rtd->codec_dai->component instead of it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/samsung/bells.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c index 34deba461ae1..0e66cd8ef2f9 100644 --- a/sound/soc/samsung/bells.c +++ b/sound/soc/samsung/bells.c @@ -60,13 +60,13 @@ static int bells_set_bias_level(struct snd_soc_card *card, { struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai *codec_dai; - struct snd_soc_codec *codec; + struct snd_soc_component *component; struct bells_drvdata *bells = card->drvdata; int ret; rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name); codec_dai = rtd->codec_dai; - codec = codec_dai->codec; + component = codec_dai->component; if (dapm->dev != codec_dai->dev) return 0; @@ -76,7 +76,7 @@ static int bells_set_bias_level(struct snd_soc_card *card, if (dapm->bias_level != SND_SOC_BIAS_STANDBY) break; - ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, + ret = snd_soc_component_set_pll(component, WM5102_FLL1, ARIZONA_FLL_SRC_MCLK1, MCLK_RATE, bells->sysclk_rate); @@ -84,7 +84,7 @@ static int bells_set_bias_level(struct snd_soc_card *card, pr_err("Failed to start FLL: %d\n", ret); if (bells->asyncclk_rate) { - ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, + ret = snd_soc_component_set_pll(component, WM5102_FLL2, ARIZONA_FLL_SRC_AIF2BCLK, BCLK2_RATE, bells->asyncclk_rate); @@ -106,27 +106,27 @@ static int bells_set_bias_level_post(struct snd_soc_card *card, { struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai *codec_dai; - struct snd_soc_codec *codec; + struct snd_soc_component *component; struct bells_drvdata *bells = card->drvdata; int ret; rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name); codec_dai = rtd->codec_dai; - codec = codec_dai->codec; + component = codec_dai->component; if (dapm->dev != codec_dai->dev) return 0; switch (level) { case SND_SOC_BIAS_STANDBY: - ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, 0, 0, 0); + ret = snd_soc_component_set_pll(component, WM5102_FLL1, 0, 0, 0); if (ret < 0) { pr_err("Failed to stop FLL: %d\n", ret); return ret; } if (bells->asyncclk_rate) { - ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, + ret = snd_soc_component_set_pll(component, WM5102_FLL2, 0, 0, 0); if (ret < 0) { pr_err("Failed to stop FLL: %d\n", ret); @@ -148,8 +148,8 @@ static int bells_late_probe(struct snd_soc_card *card) { struct bells_drvdata *bells = card->drvdata; struct snd_soc_pcm_runtime *rtd; - struct snd_soc_codec *wm0010; - struct snd_soc_codec *codec; + struct snd_soc_component *wm0010; + struct snd_soc_component *component; struct snd_soc_dai *aif1_dai; struct snd_soc_dai *aif2_dai; struct snd_soc_dai *aif3_dai; @@ -157,22 +157,22 @@ static int bells_late_probe(struct snd_soc_card *card) int ret; rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_AP_DSP].name); - wm0010 = rtd->codec; + wm0010 = rtd->codec_dai->component; rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name); - codec = rtd->codec; + component = rtd->codec_dai->component; aif1_dai = rtd->codec_dai; - ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, + ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK, ARIZONA_CLK_SRC_FLL1, bells->sysclk_rate, SND_SOC_CLOCK_IN); if (ret != 0) { - dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret); + dev_err(component->dev, "Failed to set SYSCLK: %d\n", ret); return ret; } - ret = snd_soc_codec_set_sysclk(wm0010, 0, 0, SYS_MCLK_RATE, 0); + ret = snd_soc_component_set_sysclk(wm0010, 0, 0, SYS_MCLK_RATE, 0); if (ret != 0) { dev_err(wm0010->dev, "Failed to set WM0010 clock: %d\n", ret); return ret; @@ -182,20 +182,20 @@ static int bells_late_probe(struct snd_soc_card *card) if (ret != 0) dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); - ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0, + ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_OPCLK, 0, SYS_MCLK_RATE, SND_SOC_CLOCK_OUT); if (ret != 0) - dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret); + dev_err(component->dev, "Failed to set OPCLK: %d\n", ret); if (card->num_rtd == DAI_CODEC_CP) return 0; - ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK, + ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_ASYNCCLK, ARIZONA_CLK_SRC_FLL2, bells->asyncclk_rate, SND_SOC_CLOCK_IN); if (ret != 0) { - dev_err(codec->dev, "Failed to set ASYNCCLK: %d\n", ret); + dev_err(component->dev, "Failed to set ASYNCCLK: %d\n", ret); return ret; } @@ -221,7 +221,7 @@ static int bells_late_probe(struct snd_soc_card *card) return ret; } - ret = snd_soc_codec_set_sysclk(wm9081_dai->codec, WM9081_SYSCLK_MCLK, + ret = snd_soc_component_set_sysclk(wm9081_dai->component, WM9081_SYSCLK_MCLK, 0, SYS_MCLK_RATE, 0); if (ret != 0) { dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret); -- cgit v1.2.3 From 2e662342962863bb6044ad581d7cc03795da4e9d Mon Sep 17 00:00:00 2001 From: Michael Stecklein Date: Tue, 5 Dec 2017 09:54:11 -0600 Subject: ASoC: tas6424: add bindings for TAS6424 Add the bindings for the TAS6424 digital amplifier. Signed-off-by: Michael Stecklein Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/ti,tas6424.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ti,tas6424.txt diff --git a/Documentation/devicetree/bindings/sound/ti,tas6424.txt b/Documentation/devicetree/bindings/sound/ti,tas6424.txt new file mode 100644 index 000000000000..1c4ada0eef4e --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,tas6424.txt @@ -0,0 +1,20 @@ +Texas Instruments TAS6424 Quad-Channel Audio amplifier + +The TAS6424 serial control bus communicates through I2C protocols. + +Required properties: + - compatible: "ti,tas6424" - TAS6424 + - reg: I2C slave address + - sound-dai-cells: must be equal to 0 + +Example: + +tas6424: tas6424@6a { + compatible = "ti,tas6424"; + reg = <0x6a>; + + #sound-dai-cells = <0>; +}; + +For more product information please see the link below: +http://www.ti.com/product/TAS6424-Q1 -- cgit v1.2.3 From 157b68babe3281222e08c9c58456ca22544f06bc Mon Sep 17 00:00:00 2001 From: Andreas Dannenberg Date: Tue, 5 Dec 2017 09:54:12 -0600 Subject: ASoC: tas6424: Add support for TAS6424 digital amplifier The Texas Instruments TAS6424 device is a high-efficiency quad-channel Class-D audio power amplifier. Its digital time division multiplexed (TDM) interface enables up to 2 devices to share the same bus, supporting a total of eight channels from one audio serial port. Signed-off-by: Andreas Dannenberg Signed-off-by: Michael Stecklein Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 8 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas6424.c | 707 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tas6424.h | 144 +++++++++ 4 files changed, 861 insertions(+) create mode 100644 sound/soc/codecs/tas6424.c create mode 100644 sound/soc/codecs/tas6424.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a42ddbc93f3d..6c2e0d5426f7 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -148,6 +148,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TAS5086 if I2C select SND_SOC_TAS571X if I2C select SND_SOC_TAS5720 if I2C + select SND_SOC_TAS6424 if I2C select SND_SOC_TFA9879 if I2C select SND_SOC_TLV320AIC23_I2C if I2C select SND_SOC_TLV320AIC23_SPI if SPI_MASTER @@ -883,6 +884,13 @@ config SND_SOC_TAS5720 Enable support for Texas Instruments TAS5720L/M high-efficiency mono Class-D audio power amplifiers. +config SND_SOC_TAS6424 + tristate "Texas Instruments TAS6424 Quad-Channel Audio amplifier" + depends on I2C + help + Enable support for Texas Instruments TAS6424 high-efficiency + digital input quad-channel Class-D audio power amplifiers. + config SND_SOC_TFA9879 tristate "NXP Semiconductors TFA9879 amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 0001069ce2a7..154abd758c30 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -156,6 +156,7 @@ snd-soc-sti-sas-objs := sti-sas.o snd-soc-tas5086-objs := tas5086.o snd-soc-tas571x-objs := tas571x.o snd-soc-tas5720-objs := tas5720.o +snd-soc-tas6424-objs := tas6424.o snd-soc-tfa9879-objs := tfa9879.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o @@ -395,6 +396,7 @@ obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o +obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c new file mode 100644 index 000000000000..49b87f6e85bf --- /dev/null +++ b/sound/soc/codecs/tas6424.c @@ -0,0 +1,707 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ALSA SoC Texas Instruments TAS6424 Quad-Channel Audio Amplifier + * + * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Andreas Dannenberg + * Andrew F. Davis + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "tas6424.h" + +/* Define how often to check (and clear) the fault status register (in ms) */ +#define TAS6424_FAULT_CHECK_INTERVAL 200 + +static const char * const tas6424_supply_names[] = { + "dvdd", /* Digital power supply. Connect to 3.3-V supply. */ + "vbat", /* Supply used for higher voltage analog circuits. */ + "pvdd", /* Class-D amp output FETs supply. */ +}; +#define TAS6424_NUM_SUPPLIES ARRAY_SIZE(tas6424_supply_names) + +struct tas6424_data { + struct device *dev; + struct regmap *regmap; + struct regulator_bulk_data supplies[TAS6424_NUM_SUPPLIES]; + struct delayed_work fault_check_work; + unsigned int last_fault1; + unsigned int last_fault2; + unsigned int last_warn; +}; + +/* + * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that + * setting the gain below -100 dB (register value <0x7) is effectively a MUTE + * as per device datasheet. + */ +static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0); + +static const struct snd_kcontrol_new tas6424_snd_controls[] = { + SOC_SINGLE_TLV("Speaker Driver CH1 Playback Volume", + TAS6424_CH1_VOL_CTRL, 0, 0xff, 0, dac_tlv), + SOC_SINGLE_TLV("Speaker Driver CH2 Playback Volume", + TAS6424_CH2_VOL_CTRL, 0, 0xff, 0, dac_tlv), + SOC_SINGLE_TLV("Speaker Driver CH3 Playback Volume", + TAS6424_CH3_VOL_CTRL, 0, 0xff, 0, dac_tlv), + SOC_SINGLE_TLV("Speaker Driver CH4 Playback Volume", + TAS6424_CH4_VOL_CTRL, 0, 0xff, 0, dac_tlv), +}; + +static int tas6424_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tas6424_data *tas6424 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s() event=0x%0x\n", __func__, event); + + if (event & SND_SOC_DAPM_POST_PMU) { + /* Observe codec shutdown-to-active time */ + msleep(12); + + /* Turn on TAS6424 periodic fault checking/handling */ + tas6424->last_fault1 = 0; + tas6424->last_fault2 = 0; + tas6424->last_warn = 0; + schedule_delayed_work(&tas6424->fault_check_work, + msecs_to_jiffies(TAS6424_FAULT_CHECK_INTERVAL)); + } else if (event & SND_SOC_DAPM_PRE_PMD) { + /* Disable TAS6424 periodic fault checking/handling */ + cancel_delayed_work_sync(&tas6424->fault_check_work); + } + + return 0; +} + +static const struct snd_soc_dapm_widget tas6424_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas6424_dac_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_OUTPUT("OUT") +}; + +static const struct snd_soc_dapm_route tas6424_audio_map[] = { + { "DAC", NULL, "DAC IN" }, + { "OUT", NULL, "DAC" }, +}; + +static int tas6424_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int rate = params_rate(params); + unsigned int width = params_width(params); + u8 sap_ctrl = 0; + + dev_dbg(codec->dev, "%s() rate=%u width=%u\n", __func__, rate, width); + + switch (rate) { + case 44100: + sap_ctrl |= TAS6424_SAP_RATE_44100; + break; + case 48000: + sap_ctrl |= TAS6424_SAP_RATE_48000; + break; + case 96000: + sap_ctrl |= TAS6424_SAP_RATE_96000; + break; + default: + dev_err(codec->dev, "unsupported sample rate: %u\n", rate); + return -EINVAL; + } + + switch (width) { + case 16: + sap_ctrl |= TAS6424_SAP_TDM_SLOT_SZ_16; + break; + case 24: + break; + default: + dev_err(codec->dev, "unsupported sample width: %u\n", width); + return -EINVAL; + } + + snd_soc_update_bits(codec, TAS6424_SAP_CTRL, + TAS6424_SAP_RATE_MASK | + TAS6424_SAP_TDM_SLOT_SZ_16, + sap_ctrl); + + return 0; +} + +static int tas6424_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + u8 serial_format = 0; + + dev_dbg(codec->dev, "%s() fmt=0x%0x\n", __func__, fmt); + + /* clock masters */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + dev_err(codec->dev, "Invalid DAI master/slave interface\n"); + return -EINVAL; + } + + /* signal polarity */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + default: + dev_err(codec->dev, "Invalid DAI clock signal polarity\n"); + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + serial_format |= TAS6424_SAP_I2S; + break; + case SND_SOC_DAIFMT_DSP_A: + serial_format |= TAS6424_SAP_DSP; + break; + case SND_SOC_DAIFMT_DSP_B: + /* + * We can use the fact that the TAS6424 does not care about the + * LRCLK duty cycle during TDM to receive DSP_B formatted data + * in LEFTJ mode (no delaying of the 1st data bit). + */ + serial_format |= TAS6424_SAP_LEFTJ; + break; + case SND_SOC_DAIFMT_LEFT_J: + serial_format |= TAS6424_SAP_LEFTJ; + break; + default: + dev_err(codec->dev, "Invalid DAI interface format\n"); + return -EINVAL; + } + + snd_soc_update_bits(codec, TAS6424_SAP_CTRL, + TAS6424_SAP_FMT_MASK, serial_format); + + return 0; +} + +static int tas6424_set_dai_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int first_slot, last_slot; + bool sap_tdm_slot_last; + + dev_dbg(codec->dev, "%s() tx_mask=%d rx_mask=%d\n", __func__, + tx_mask, rx_mask); + + if (!tx_mask || !rx_mask) + return 0; /* nothing needed to disable TDM mode */ + + /* + * Determine the first slot and last slot that is being requested so + * we'll be able to more easily enforce certain constraints as the + * TAS6424's TDM interface is not fully configurable. + */ + first_slot = __ffs(tx_mask); + last_slot = __fls(rx_mask); + + if (last_slot - first_slot != 4) { + dev_err(codec->dev, "tdm mask must cover 4 contiguous slots\n"); + return -EINVAL; + } + + switch (first_slot) { + case 0: + sap_tdm_slot_last = false; + break; + case 4: + sap_tdm_slot_last = true; + break; + default: + dev_err(codec->dev, "tdm mask must start at slot 0 or 4\n"); + return -EINVAL; + } + + snd_soc_update_bits(codec, TAS6424_SAP_CTRL, TAS6424_SAP_TDM_SLOT_LAST, + sap_tdm_slot_last ? TAS6424_SAP_TDM_SLOT_LAST : 0); + + return 0; +} + +static int tas6424_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int val; + + dev_dbg(codec->dev, "%s() mute=%d\n", __func__, mute); + + if (mute) + val = TAS6424_ALL_STATE_MUTE; + else + val = TAS6424_ALL_STATE_PLAY; + + snd_soc_write(codec, TAS6424_CH_STATE_CTRL, val); + + return 0; +} + +static int tas6424_power_off(struct snd_soc_codec *codec) +{ + struct tas6424_data *tas6424 = snd_soc_codec_get_drvdata(codec); + int ret; + + snd_soc_write(codec, TAS6424_CH_STATE_CTRL, TAS6424_ALL_STATE_HIZ); + + regcache_cache_only(tas6424->regmap, true); + regcache_mark_dirty(tas6424->regmap); + + ret = regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies), + tas6424->supplies); + if (ret < 0) { + dev_err(codec->dev, "failed to disable supplies: %d\n", ret); + return ret; + } + + return 0; +} + +static int tas6424_power_on(struct snd_soc_codec *codec) +{ + struct tas6424_data *tas6424 = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(tas6424->supplies), + tas6424->supplies); + if (ret < 0) { + dev_err(codec->dev, "failed to enable supplies: %d\n", ret); + return ret; + } + + regcache_cache_only(tas6424->regmap, false); + + ret = regcache_sync(tas6424->regmap); + if (ret < 0) { + dev_err(codec->dev, "failed to sync regcache: %d\n", ret); + return ret; + } + + snd_soc_write(codec, TAS6424_CH_STATE_CTRL, TAS6424_ALL_STATE_MUTE); + + /* any time we come out of HIZ, the output channels automatically run DC + * load diagnostics, wait here until this completes + */ + msleep(230); + + return 0; +} + +static int tas6424_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + dev_dbg(codec->dev, "%s() level=%d\n", __func__, level); + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) + tas6424_power_on(codec); + break; + case SND_SOC_BIAS_OFF: + tas6424_power_off(codec); + break; + } + + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_tas6424 = { + .set_bias_level = tas6424_set_bias_level, + .idle_bias_off = true, + + .component_driver = { + .controls = tas6424_snd_controls, + .num_controls = ARRAY_SIZE(tas6424_snd_controls), + .dapm_widgets = tas6424_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tas6424_dapm_widgets), + .dapm_routes = tas6424_audio_map, + .num_dapm_routes = ARRAY_SIZE(tas6424_audio_map), + }, +}; + +static struct snd_soc_dai_ops tas6424_speaker_dai_ops = { + .hw_params = tas6424_hw_params, + .set_fmt = tas6424_set_dai_fmt, + .set_tdm_slot = tas6424_set_dai_tdm_slot, + .digital_mute = tas6424_mute, +}; + +static struct snd_soc_dai_driver tas6424_dai[] = { + { + .name = "tas6424-amplifier", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 4, + .rates = TAS6424_RATES, + .formats = TAS6424_FORMATS, + }, + .ops = &tas6424_speaker_dai_ops, + }, +}; + +static void tas6424_fault_check_work(struct work_struct *work) +{ + struct tas6424_data *tas6424 = container_of(work, struct tas6424_data, + fault_check_work.work); + struct device *dev = tas6424->dev; + unsigned int reg; + int ret; + + ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT1, ®); + if (ret < 0) { + dev_err(dev, "failed to read FAULT1 register: %d\n", ret); + goto out; + } + + /* + * Ignore any clock faults as there is no clean way to check for them. + * We would need to start checking for those faults *after* the SAIF + * stream has been setup, and stop checking *before* the stream is + * stopped to avoid any false-positives. However there are no + * appropriate hooks to monitor these events. + */ + reg &= TAS6424_FAULT_PVDD_OV | + TAS6424_FAULT_VBAT_OV | + TAS6424_FAULT_PVDD_UV | + TAS6424_FAULT_VBAT_UV; + + if (reg) + goto check_global_fault2_reg; + + /* + * Only flag errors once for a given occurrence. This is needed as + * the TAS6424 will take time clearing the fault condition internally + * during which we don't want to bombard the system with the same + * error message over and over. + */ + if ((reg & TAS6424_FAULT_PVDD_OV) && !(tas6424->last_fault1 & TAS6424_FAULT_PVDD_OV)) + dev_crit(dev, "experienced a PVDD overvoltage fault\n"); + + if ((reg & TAS6424_FAULT_VBAT_OV) && !(tas6424->last_fault1 & TAS6424_FAULT_VBAT_OV)) + dev_crit(dev, "experienced a VBAT overvoltage fault\n"); + + if ((reg & TAS6424_FAULT_PVDD_UV) && !(tas6424->last_fault1 & TAS6424_FAULT_PVDD_UV)) + dev_crit(dev, "experienced a PVDD undervoltage fault\n"); + + if ((reg & TAS6424_FAULT_VBAT_UV) && !(tas6424->last_fault1 & TAS6424_FAULT_VBAT_UV)) + dev_crit(dev, "experienced a VBAT undervoltage fault\n"); + + /* Store current fault1 value so we can detect any changes next time */ + tas6424->last_fault1 = reg; + +check_global_fault2_reg: + ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT2, ®); + if (ret < 0) { + dev_err(dev, "failed to read FAULT2 register: %d\n", ret); + goto out; + } + + reg &= TAS6424_FAULT_OTSD | + TAS6424_FAULT_OTSD_CH1 | + TAS6424_FAULT_OTSD_CH2 | + TAS6424_FAULT_OTSD_CH3 | + TAS6424_FAULT_OTSD_CH4; + + if (!reg) + goto check_warn_reg; + + if ((reg & TAS6424_FAULT_OTSD) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD)) + dev_crit(dev, "experienced a global overtemp shutdown\n"); + + if ((reg & TAS6424_FAULT_OTSD_CH1) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH1)) + dev_crit(dev, "experienced an overtemp shutdown on CH1\n"); + + if ((reg & TAS6424_FAULT_OTSD_CH2) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH2)) + dev_crit(dev, "experienced an overtemp shutdown on CH2\n"); + + if ((reg & TAS6424_FAULT_OTSD_CH3) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH3)) + dev_crit(dev, "experienced an overtemp shutdown on CH3\n"); + + if ((reg & TAS6424_FAULT_OTSD_CH4) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH4)) + dev_crit(dev, "experienced an overtemp shutdown on CH4\n"); + + /* Store current fault2 value so we can detect any changes next time */ + tas6424->last_fault2 = reg; + +check_warn_reg: + ret = regmap_read(tas6424->regmap, TAS6424_WARN, ®); + if (ret < 0) { + dev_err(dev, "failed to read WARN register: %d\n", ret); + goto out; + } + + reg &= TAS6424_WARN_VDD_UV | + TAS6424_WARN_VDD_POR | + TAS6424_WARN_VDD_OTW | + TAS6424_WARN_VDD_OTW_CH1 | + TAS6424_WARN_VDD_OTW_CH2 | + TAS6424_WARN_VDD_OTW_CH3 | + TAS6424_WARN_VDD_OTW_CH4; + + if (!reg) + goto out; + + if ((reg & TAS6424_WARN_VDD_UV) && !(tas6424->last_warn & TAS6424_WARN_VDD_UV)) + dev_warn(dev, "experienced a VDD under voltage condition\n"); + + if ((reg & TAS6424_WARN_VDD_POR) && !(tas6424->last_warn & TAS6424_WARN_VDD_POR)) + dev_warn(dev, "experienced a VDD POR condition\n"); + + if ((reg & TAS6424_WARN_VDD_OTW) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW)) + dev_warn(dev, "experienced a global overtemp warning\n"); + + if ((reg & TAS6424_WARN_VDD_OTW_CH1) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH1)) + dev_warn(dev, "experienced an overtemp warning on CH1\n"); + + if ((reg & TAS6424_WARN_VDD_OTW_CH2) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH2)) + dev_warn(dev, "experienced an overtemp warning on CH2\n"); + + if ((reg & TAS6424_WARN_VDD_OTW_CH3) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH3)) + dev_warn(dev, "experienced an overtemp warning on CH3\n"); + + if ((reg & TAS6424_WARN_VDD_OTW_CH4) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH4)) + dev_warn(dev, "experienced an overtemp warning on CH4\n"); + + /* Store current warn value so we can detect any changes next time */ + tas6424->last_warn = reg; + + /* Clear any faults by toggling the CLEAR_FAULT control bit */ + ret = regmap_write_bits(tas6424->regmap, TAS6424_MISC_CTRL3, + TAS6424_CLEAR_FAULT, TAS6424_CLEAR_FAULT); + if (ret < 0) + dev_err(dev, "failed to write MISC_CTRL3 register: %d\n", ret); + + ret = regmap_write_bits(tas6424->regmap, TAS6424_MISC_CTRL3, + TAS6424_CLEAR_FAULT, 0); + if (ret < 0) + dev_err(dev, "failed to write MISC_CTRL3 register: %d\n", ret); + +out: + /* Schedule the next fault check at the specified interval */ + schedule_delayed_work(&tas6424->fault_check_work, + msecs_to_jiffies(TAS6424_FAULT_CHECK_INTERVAL)); +} + +static const struct reg_default tas6424_reg_defaults[] = { + { TAS6424_MODE_CTRL, 0x00 }, + { TAS6424_MISC_CTRL1, 0x32 }, + { TAS6424_MISC_CTRL2, 0x62 }, + { TAS6424_SAP_CTRL, 0x04 }, + { TAS6424_CH_STATE_CTRL, 0x55 }, + { TAS6424_CH1_VOL_CTRL, 0xcf }, + { TAS6424_CH2_VOL_CTRL, 0xcf }, + { TAS6424_CH3_VOL_CTRL, 0xcf }, + { TAS6424_CH4_VOL_CTRL, 0xcf }, + { TAS6424_DC_DIAG_CTRL1, 0x00 }, + { TAS6424_DC_DIAG_CTRL2, 0x11 }, + { TAS6424_DC_DIAG_CTRL3, 0x11 }, + { TAS6424_PIN_CTRL, 0xff }, + { TAS6424_AC_DIAG_CTRL1, 0x00 }, + { TAS6424_MISC_CTRL3, 0x00 }, + { TAS6424_CLIP_CTRL, 0x01 }, + { TAS6424_CLIP_WINDOW, 0x14 }, + { TAS6424_CLIP_WARN, 0x00 }, + { TAS6424_CBC_STAT, 0x00 }, + { TAS6424_MISC_CTRL4, 0x40 }, +}; + +static bool tas6424_is_writable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TAS6424_MODE_CTRL: + case TAS6424_MISC_CTRL1: + case TAS6424_MISC_CTRL2: + case TAS6424_SAP_CTRL: + case TAS6424_CH_STATE_CTRL: + case TAS6424_CH1_VOL_CTRL: + case TAS6424_CH2_VOL_CTRL: + case TAS6424_CH3_VOL_CTRL: + case TAS6424_CH4_VOL_CTRL: + case TAS6424_DC_DIAG_CTRL1: + case TAS6424_DC_DIAG_CTRL2: + case TAS6424_DC_DIAG_CTRL3: + case TAS6424_PIN_CTRL: + case TAS6424_AC_DIAG_CTRL1: + case TAS6424_MISC_CTRL3: + case TAS6424_CLIP_CTRL: + case TAS6424_CLIP_WINDOW: + case TAS6424_CLIP_WARN: + case TAS6424_CBC_STAT: + case TAS6424_MISC_CTRL4: + return true; + default: + return false; + } +} + +static bool tas6424_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TAS6424_DC_LOAD_DIAG_REP12: + case TAS6424_DC_LOAD_DIAG_REP34: + case TAS6424_DC_LOAD_DIAG_REPLO: + case TAS6424_CHANNEL_STATE: + case TAS6424_CHANNEL_FAULT: + case TAS6424_GLOB_FAULT1: + case TAS6424_GLOB_FAULT2: + case TAS6424_WARN: + case TAS6424_AC_LOAD_DIAG_REP1: + case TAS6424_AC_LOAD_DIAG_REP2: + case TAS6424_AC_LOAD_DIAG_REP3: + case TAS6424_AC_LOAD_DIAG_REP4: + return true; + default: + return false; + } +} + +static const struct regmap_config tas6424_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .writeable_reg = tas6424_is_writable_reg, + .volatile_reg = tas6424_is_volatile_reg, + + .max_register = TAS6424_MAX, + .reg_defaults = tas6424_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tas6424_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id tas6424_of_ids[] = { + { .compatible = "ti,tas6424", }, + { }, +}; +MODULE_DEVICE_TABLE(of, tas6424_of_ids); +#endif + +static int tas6424_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct tas6424_data *tas6424; + int ret; + int i; + + tas6424 = devm_kzalloc(dev, sizeof(*tas6424), GFP_KERNEL); + if (!tas6424) + return -ENOMEM; + dev_set_drvdata(dev, tas6424); + + tas6424->dev = dev; + + tas6424->regmap = devm_regmap_init_i2c(client, &tas6424_regmap_config); + if (IS_ERR(tas6424->regmap)) { + ret = PTR_ERR(tas6424->regmap); + dev_err(dev, "unable to allocate register map: %d\n", ret); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(tas6424->supplies); i++) + tas6424->supplies[i].supply = tas6424_supply_names[i]; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(tas6424->supplies), + tas6424->supplies); + if (ret) { + dev_err(dev, "unable to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(tas6424->supplies), + tas6424->supplies); + if (ret) { + dev_err(dev, "unable to enable supplies: %d\n", ret); + return ret; + } + + /* Reset device to establish well-defined startup state */ + ret = regmap_update_bits(tas6424->regmap, TAS6424_MODE_CTRL, + TAS6424_RESET, TAS6424_RESET); + if (ret) { + dev_err(dev, "unable to reset device: %d\n", ret); + return ret; + } + + INIT_DELAYED_WORK(&tas6424->fault_check_work, tas6424_fault_check_work); + + ret = snd_soc_register_codec(dev, &soc_codec_dev_tas6424, + tas6424_dai, ARRAY_SIZE(tas6424_dai)); + if (ret < 0) { + dev_err(dev, "unable to register codec: %d\n", ret); + return ret; + } + + return 0; +} + +static int tas6424_i2c_remove(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct tas6424_data *tas6424 = dev_get_drvdata(dev); + int ret; + + snd_soc_unregister_codec(dev); + + cancel_delayed_work_sync(&tas6424->fault_check_work); + + ret = regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies), + tas6424->supplies); + if (ret < 0) { + dev_err(dev, "unable to disable supplies: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct i2c_device_id tas6424_i2c_ids[] = { + { "tas6424", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tas6424_i2c_ids); + +static struct i2c_driver tas6424_i2c_driver = { + .driver = { + .name = "tas6424", + .of_match_table = of_match_ptr(tas6424_of_ids), + }, + .probe = tas6424_i2c_probe, + .remove = tas6424_i2c_remove, + .id_table = tas6424_i2c_ids, +}; +module_i2c_driver(tas6424_i2c_driver); + +MODULE_AUTHOR("Andreas Dannenberg "); +MODULE_AUTHOR("Andrew F. Davis "); +MODULE_DESCRIPTION("TAS6424 Audio amplifier driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/tas6424.h b/sound/soc/codecs/tas6424.h new file mode 100644 index 000000000000..430588328a06 --- /dev/null +++ b/sound/soc/codecs/tas6424.h @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ALSA SoC Texas Instruments TAS6424 Quad-Channel Audio Amplifier + * + * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Andreas Dannenberg + * Andrew F. Davis + */ + +#ifndef __TAS6424_H__ +#define __TAS6424_H__ + +#define TAS6424_RATES (SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000) + +#define TAS6424_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +/* Register Address Map */ +#define TAS6424_MODE_CTRL 0x00 +#define TAS6424_MISC_CTRL1 0x01 +#define TAS6424_MISC_CTRL2 0x02 +#define TAS6424_SAP_CTRL 0x03 +#define TAS6424_CH_STATE_CTRL 0x04 +#define TAS6424_CH1_VOL_CTRL 0x05 +#define TAS6424_CH2_VOL_CTRL 0x06 +#define TAS6424_CH3_VOL_CTRL 0x07 +#define TAS6424_CH4_VOL_CTRL 0x08 +#define TAS6424_DC_DIAG_CTRL1 0x09 +#define TAS6424_DC_DIAG_CTRL2 0x0a +#define TAS6424_DC_DIAG_CTRL3 0x0b +#define TAS6424_DC_LOAD_DIAG_REP12 0x0c +#define TAS6424_DC_LOAD_DIAG_REP34 0x0d +#define TAS6424_DC_LOAD_DIAG_REPLO 0x0e +#define TAS6424_CHANNEL_STATE 0x0f +#define TAS6424_CHANNEL_FAULT 0x10 +#define TAS6424_GLOB_FAULT1 0x11 +#define TAS6424_GLOB_FAULT2 0x12 +#define TAS6424_WARN 0x13 +#define TAS6424_PIN_CTRL 0x14 +#define TAS6424_AC_DIAG_CTRL1 0x15 +#define TAS6424_AC_DIAG_CTRL2 0x16 +#define TAS6424_AC_LOAD_DIAG_REP1 0x17 +#define TAS6424_AC_LOAD_DIAG_REP2 0x18 +#define TAS6424_AC_LOAD_DIAG_REP3 0x19 +#define TAS6424_AC_LOAD_DIAG_REP4 0x1a +#define TAS6424_MISC_CTRL3 0x21 +#define TAS6424_CLIP_CTRL 0x22 +#define TAS6424_CLIP_WINDOW 0x23 +#define TAS6424_CLIP_WARN 0x24 +#define TAS6424_CBC_STAT 0x25 +#define TAS6424_MISC_CTRL4 0x26 +#define TAS6424_MAX TAS6424_MISC_CTRL4 + +/* TAS6424_MODE_CTRL_REG */ +#define TAS6424_RESET BIT(7) + +/* TAS6424_SAP_CTRL_REG */ +#define TAS6424_SAP_RATE_MASK GENMASK(7, 6) +#define TAS6424_SAP_RATE_44100 (0x00 << 6) +#define TAS6424_SAP_RATE_48000 (0x01 << 6) +#define TAS6424_SAP_RATE_96000 (0x02 << 6) +#define TAS6424_SAP_TDM_SLOT_LAST BIT(5) +#define TAS6424_SAP_TDM_SLOT_SZ_16 BIT(4) +#define TAS6424_SAP_TDM_SLOT_SWAP BIT(3) +#define TAS6424_SAP_FMT_MASK GENMASK(2, 0) +#define TAS6424_SAP_RIGHTJ_24 (0x00 << 0) +#define TAS6424_SAP_RIGHTJ_20 (0x01 << 0) +#define TAS6424_SAP_RIGHTJ_18 (0x02 << 0) +#define TAS6424_SAP_RIGHTJ_16 (0x03 << 0) +#define TAS6424_SAP_I2S (0x04 << 0) +#define TAS6424_SAP_LEFTJ (0x05 << 0) +#define TAS6424_SAP_DSP (0x06 << 0) + +/* TAS6424_CH_STATE_CTRL_REG */ +#define TAS6424_CH1_STATE_MASK GENMASK(7, 6) +#define TAS6424_CH1_STATE_PLAY (0x00 << 6) +#define TAS6424_CH1_STATE_HIZ (0x01 << 6) +#define TAS6424_CH1_STATE_MUTE (0x02 << 6) +#define TAS6424_CH1_STATE_DIAG (0x03 << 6) +#define TAS6424_CH2_STATE_MASK GENMASK(5, 4) +#define TAS6424_CH2_STATE_PLAY (0x00 << 4) +#define TAS6424_CH2_STATE_HIZ (0x01 << 4) +#define TAS6424_CH2_STATE_MUTE (0x02 << 4) +#define TAS6424_CH2_STATE_DIAG (0x03 << 4) +#define TAS6424_CH3_STATE_MASK GENMASK(3, 2) +#define TAS6424_CH3_STATE_PLAY (0x00 << 2) +#define TAS6424_CH3_STATE_HIZ (0x01 << 2) +#define TAS6424_CH3_STATE_MUTE (0x02 << 2) +#define TAS6424_CH3_STATE_DIAG (0x03 << 2) +#define TAS6424_CH4_STATE_MASK GENMASK(1, 0) +#define TAS6424_CH4_STATE_PLAY (0x00 << 0) +#define TAS6424_CH4_STATE_HIZ (0x01 << 0) +#define TAS6424_CH4_STATE_MUTE (0x02 << 0) +#define TAS6424_CH4_STATE_DIAG (0x03 << 0) +#define TAS6424_ALL_STATE_PLAY (TAS6424_CH1_STATE_PLAY | \ + TAS6424_CH2_STATE_PLAY | \ + TAS6424_CH3_STATE_PLAY | \ + TAS6424_CH4_STATE_PLAY) +#define TAS6424_ALL_STATE_HIZ (TAS6424_CH1_STATE_HIZ | \ + TAS6424_CH2_STATE_HIZ | \ + TAS6424_CH3_STATE_HIZ | \ + TAS6424_CH4_STATE_HIZ) +#define TAS6424_ALL_STATE_MUTE (TAS6424_CH1_STATE_MUTE | \ + TAS6424_CH2_STATE_MUTE | \ + TAS6424_CH3_STATE_MUTE | \ + TAS6424_CH4_STATE_MUTE) +#define TAS6424_ALL_STATE_DIAG (TAS6424_CH1_STATE_DIAG | \ + TAS6424_CH2_STATE_DIAG | \ + TAS6424_CH3_STATE_DIAG | \ + TAS6424_CH4_STATE_DIAG) + +/* TAS6424_GLOB_FAULT1_REG */ +#define TAS6424_FAULT_CLOCK BIT(4) +#define TAS6424_FAULT_PVDD_OV BIT(3) +#define TAS6424_FAULT_VBAT_OV BIT(2) +#define TAS6424_FAULT_PVDD_UV BIT(1) +#define TAS6424_FAULT_VBAT_UV BIT(0) + +/* TAS6424_GLOB_FAULT2_REG */ +#define TAS6424_FAULT_OTSD BIT(4) +#define TAS6424_FAULT_OTSD_CH1 BIT(3) +#define TAS6424_FAULT_OTSD_CH2 BIT(2) +#define TAS6424_FAULT_OTSD_CH3 BIT(1) +#define TAS6424_FAULT_OTSD_CH4 BIT(0) + +/* TAS6424_WARN_REG */ +#define TAS6424_WARN_VDD_UV BIT(6) +#define TAS6424_WARN_VDD_POR BIT(5) +#define TAS6424_WARN_VDD_OTW BIT(4) +#define TAS6424_WARN_VDD_OTW_CH1 BIT(3) +#define TAS6424_WARN_VDD_OTW_CH2 BIT(2) +#define TAS6424_WARN_VDD_OTW_CH3 BIT(1) +#define TAS6424_WARN_VDD_OTW_CH4 BIT(0) + +/* TAS6424_MISC_CTRL3_REG */ +#define TAS6424_CLEAR_FAULT BIT(7) +#define TAS6424_PBTL_CH_SEL BIT(6) +#define TAS6424_MASK_CBC_WARN BIT(5) +#define TAS6424_MASK_VDD_UV BIT(4) +#define TAS6424_OTSD_AUTO_RECOVERY BIT(3) + +#endif /* __TAS6424_H__ */ -- cgit v1.2.3 From 993a3450712b2a723689b6b6b1a7fe6fe053708e Mon Sep 17 00:00:00 2001 From: Andreas Dannenberg Date: Tue, 5 Dec 2017 14:52:56 -0600 Subject: ASoC: pcm186x: Add initial PCM1862/63/64/65 universal ADC driver This is an initial version of the PCM186x codec driver supporting both 2-channel and 4-channel device variants. Not all device features are supported yet such as master/slave mode PLL configuration for which the codec driver currently relies on the PCM186x built-in clock auto-detection feature or the connection of digital microphones. However here is what's here and what should work: - Support for SPI and I2C low-level interfaces - Regmap support and basic register definitions - Input Mixer and Mux selection - I2C, LJ, and TDM DAI format support Signed-off-by: Andreas Dannenberg Signed-off-by: Michael Stecklein Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 17 + sound/soc/codecs/Makefile | 6 + sound/soc/codecs/pcm186x-i2c.c | 69 ++++ sound/soc/codecs/pcm186x-spi.c | 69 ++++ sound/soc/codecs/pcm186x.c | 719 +++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/pcm186x.h | 220 +++++++++++++ 6 files changed, 1100 insertions(+) create mode 100644 sound/soc/codecs/pcm186x-i2c.c create mode 100644 sound/soc/codecs/pcm186x-spi.c create mode 100644 sound/soc/codecs/pcm186x.c create mode 100644 sound/soc/codecs/pcm186x.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a42ddbc93f3d..dda8c01170b3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -109,6 +109,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM1681 if I2C select SND_SOC_PCM179X_I2C if I2C select SND_SOC_PCM179X_SPI if SPI_MASTER + select SND_SOC_PCM186X_I2C if I2C + select SND_SOC_PCM186X_SPI if SPI_MASTER select SND_SOC_PCM3008 select SND_SOC_PCM3168A_I2C if I2C select SND_SOC_PCM3168A_SPI if SPI_MASTER @@ -661,6 +663,21 @@ config SND_SOC_PCM179X_SPI Enable support for Texas Instruments PCM179x CODEC. Select this if your PCM179x is connected via an SPI bus. +config SND_SOC_PCM186X + tristate + +config SND_SOC_PCM186X_I2C + tristate "Texas Instruments PCM186x CODECs - I2C" + depends on I2C + select SND_SOC_PCM186X + select REGMAP_I2C + +config SND_SOC_PCM186X_SPI + tristate "Texas Instruments PCM186x CODECs - SPI" + depends on SPI_MASTER + select SND_SOC_PCM186X + select REGMAP_SPI + config SND_SOC_PCM3008 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 0001069ce2a7..146e48a60098 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -105,6 +105,9 @@ snd-soc-pcm1681-objs := pcm1681.o snd-soc-pcm179x-codec-objs := pcm179x.o snd-soc-pcm179x-i2c-objs := pcm179x-i2c.o snd-soc-pcm179x-spi-objs := pcm179x-spi.o +snd-soc-pcm186x-objs := pcm186x.o +snd-soc-pcm186x-i2c-objs := pcm186x-i2c.o +snd-soc-pcm186x-spi-objs := pcm186x-spi.o snd-soc-pcm3008-objs := pcm3008.o snd-soc-pcm3168a-objs := pcm3168a.o snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o @@ -345,6 +348,9 @@ obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o obj-$(CONFIG_SND_SOC_PCM179X_I2C) += snd-soc-pcm179x-i2c.o obj-$(CONFIG_SND_SOC_PCM179X_SPI) += snd-soc-pcm179x-spi.o +obj-$(CONFIG_SND_SOC_PCM186X) += snd-soc-pcm186x.o +obj-$(CONFIG_SND_SOC_PCM186X_I2C) += snd-soc-pcm186x-i2c.o +obj-$(CONFIG_SND_SOC_PCM186X_SPI) += snd-soc-pcm186x-spi.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o diff --git a/sound/soc/codecs/pcm186x-i2c.c b/sound/soc/codecs/pcm186x-i2c.c new file mode 100644 index 000000000000..543621232d60 --- /dev/null +++ b/sound/soc/codecs/pcm186x-i2c.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Texas Instruments PCM186x Universal Audio ADC - I2C + * + * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com + * Andreas Dannenberg + * Andrew F. Davis + */ + +#include +#include +#include + +#include "pcm186x.h" + +static const struct of_device_id pcm186x_of_match[] = { + { .compatible = "ti,pcm1862", .data = (void *)PCM1862 }, + { .compatible = "ti,pcm1863", .data = (void *)PCM1863 }, + { .compatible = "ti,pcm1864", .data = (void *)PCM1864 }, + { .compatible = "ti,pcm1865", .data = (void *)PCM1865 }, + { } +}; +MODULE_DEVICE_TABLE(of, pcm186x_of_match); + +static int pcm186x_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + const enum pcm186x_type type = (enum pcm186x_type)id->driver_data; + int irq = i2c->irq; + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(i2c, &pcm186x_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return pcm186x_probe(&i2c->dev, type, irq, regmap); +} + +static int pcm186x_i2c_remove(struct i2c_client *i2c) +{ + pcm186x_remove(&i2c->dev); + + return 0; +} + +static const struct i2c_device_id pcm186x_i2c_id[] = { + { "pcm1862", PCM1862 }, + { "pcm1863", PCM1863 }, + { "pcm1864", PCM1864 }, + { "pcm1865", PCM1865 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcm186x_i2c_id); + +static struct i2c_driver pcm186x_i2c_driver = { + .probe = pcm186x_i2c_probe, + .remove = pcm186x_i2c_remove, + .id_table = pcm186x_i2c_id, + .driver = { + .name = "pcm186x", + .of_match_table = pcm186x_of_match, + }, +}; +module_i2c_driver(pcm186x_i2c_driver); + +MODULE_AUTHOR("Andreas Dannenberg "); +MODULE_AUTHOR("Andrew F. Davis "); +MODULE_DESCRIPTION("PCM186x Universal Audio ADC I2C Interface Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm186x-spi.c b/sound/soc/codecs/pcm186x-spi.c new file mode 100644 index 000000000000..2366f8e4d4d4 --- /dev/null +++ b/sound/soc/codecs/pcm186x-spi.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Texas Instruments PCM186x Universal Audio ADC - SPI + * + * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com + * Andreas Dannenberg + * Andrew F. Davis + */ + +#include +#include +#include + +#include "pcm186x.h" + +static const struct of_device_id pcm186x_of_match[] = { + { .compatible = "ti,pcm1862", .data = (void *)PCM1862 }, + { .compatible = "ti,pcm1863", .data = (void *)PCM1863 }, + { .compatible = "ti,pcm1864", .data = (void *)PCM1864 }, + { .compatible = "ti,pcm1865", .data = (void *)PCM1865 }, + { } +}; +MODULE_DEVICE_TABLE(of, pcm186x_of_match); + +static int pcm186x_spi_probe(struct spi_device *spi) +{ + const enum pcm186x_type type = + (enum pcm186x_type)spi_get_device_id(spi)->driver_data; + int irq = spi->irq; + struct regmap *regmap; + + regmap = devm_regmap_init_spi(spi, &pcm186x_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return pcm186x_probe(&spi->dev, type, irq, regmap); +} + +static int pcm186x_spi_remove(struct spi_device *spi) +{ + pcm186x_remove(&spi->dev); + + return 0; +} + +static const struct spi_device_id pcm186x_spi_id[] = { + { "pcm1862", PCM1862 }, + { "pcm1863", PCM1863 }, + { "pcm1864", PCM1864 }, + { "pcm1865", PCM1865 }, + { } +}; +MODULE_DEVICE_TABLE(spi, pcm186x_spi_id); + +static struct spi_driver pcm186x_spi_driver = { + .probe = pcm186x_spi_probe, + .remove = pcm186x_spi_remove, + .id_table = pcm186x_spi_id, + .driver = { + .name = "pcm186x", + .of_match_table = pcm186x_of_match, + }, +}; +module_spi_driver(pcm186x_spi_driver); + +MODULE_AUTHOR("Andreas Dannenberg "); +MODULE_AUTHOR("Andrew F. Davis "); +MODULE_DESCRIPTION("PCM186x Universal Audio ADC SPI Interface Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c new file mode 100644 index 000000000000..f7aa56e20169 --- /dev/null +++ b/sound/soc/codecs/pcm186x.c @@ -0,0 +1,719 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Texas Instruments PCM186x Universal Audio ADC + * + * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com + * Andreas Dannenberg + * Andrew F. Davis + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcm186x.h" + +static const char * const pcm186x_supply_names[] = { + "avdd", /* Analog power supply. Connect to 3.3-V supply. */ + "dvdd", /* Digital power supply. Connect to 3.3-V supply. */ + "iovdd", /* I/O power supply. Connect to 3.3-V or 1.8-V. */ +}; +#define PCM186x_NUM_SUPPLIES ARRAY_SIZE(pcm186x_supply_names) + +struct pcm186x_priv { + struct regmap *regmap; + struct regulator_bulk_data supplies[PCM186x_NUM_SUPPLIES]; + unsigned int sysclk; + unsigned int tdm_offset; + bool is_tdm_mode; + bool is_master_mode; +}; + +static const DECLARE_TLV_DB_SCALE(pcm186x_pga_tlv, -1200, 4000, 50); + +static const struct snd_kcontrol_new pcm1863_snd_controls[] = { + SOC_DOUBLE_R_S_TLV("ADC Capture Volume", PCM186X_PGA_VAL_CH1_L, + PCM186X_PGA_VAL_CH1_R, 0, -24, 80, 7, 0, + pcm186x_pga_tlv), +}; + +static const struct snd_kcontrol_new pcm1865_snd_controls[] = { + SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", PCM186X_PGA_VAL_CH1_L, + PCM186X_PGA_VAL_CH1_R, 0, -24, 80, 7, 0, + pcm186x_pga_tlv), + SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", PCM186X_PGA_VAL_CH2_L, + PCM186X_PGA_VAL_CH2_R, 0, -24, 80, 7, 0, + pcm186x_pga_tlv), +}; + +const unsigned int pcm186x_adc_input_channel_sel_value[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x20, 0x30 +}; + +static const char * const pcm186x_adcl_input_channel_sel_text[] = { + "No Select", + "VINL1[SE]", /* Default for ADC1L */ + "VINL2[SE]", /* Default for ADC2L */ + "VINL2[SE] + VINL1[SE]", + "VINL3[SE]", + "VINL3[SE] + VINL1[SE]", + "VINL3[SE] + VINL2[SE]", + "VINL3[SE] + VINL2[SE] + VINL1[SE]", + "VINL4[SE]", + "VINL4[SE] + VINL1[SE]", + "VINL4[SE] + VINL2[SE]", + "VINL4[SE] + VINL2[SE] + VINL1[SE]", + "VINL4[SE] + VINL3[SE]", + "VINL4[SE] + VINL3[SE] + VINL1[SE]", + "VINL4[SE] + VINL3[SE] + VINL2[SE]", + "VINL4[SE] + VINL3[SE] + VINL2[SE] + VINL1[SE]", + "{VIN1P, VIN1M}[DIFF]", + "{VIN4P, VIN4M}[DIFF]", + "{VIN1P, VIN1M}[DIFF] + {VIN4P, VIN4M}[DIFF]" +}; + +static const char * const pcm186x_adcr_input_channel_sel_text[] = { + "No Select", + "VINR1[SE]", /* Default for ADC1R */ + "VINR2[SE]", /* Default for ADC2R */ + "VINR2[SE] + VINR1[SE]", + "VINR3[SE]", + "VINR3[SE] + VINR1[SE]", + "VINR3[SE] + VINR2[SE]", + "VINR3[SE] + VINR2[SE] + VINR1[SE]", + "VINR4[SE]", + "VINR4[SE] + VINR1[SE]", + "VINR4[SE] + VINR2[SE]", + "VINR4[SE] + VINR2[SE] + VINR1[SE]", + "VINR4[SE] + VINR3[SE]", + "VINR4[SE] + VINR3[SE] + VINR1[SE]", + "VINR4[SE] + VINR3[SE] + VINR2[SE]", + "VINR4[SE] + VINR3[SE] + VINR2[SE] + VINR1[SE]", + "{VIN2P, VIN2M}[DIFF]", + "{VIN3P, VIN3M}[DIFF]", + "{VIN2P, VIN2M}[DIFF] + {VIN3P, VIN3M}[DIFF]" +}; + +static const struct soc_enum pcm186x_adc_input_channel_sel[] = { + SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0, + PCM186X_ADC_INPUT_SEL_MASK, + ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text), + pcm186x_adcl_input_channel_sel_text, + pcm186x_adc_input_channel_sel_value), + SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0, + PCM186X_ADC_INPUT_SEL_MASK, + ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text), + pcm186x_adcr_input_channel_sel_text, + pcm186x_adc_input_channel_sel_value), + SOC_VALUE_ENUM_SINGLE(PCM186X_ADC2_INPUT_SEL_L, 0, + PCM186X_ADC_INPUT_SEL_MASK, + ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text), + pcm186x_adcl_input_channel_sel_text, + pcm186x_adc_input_channel_sel_value), + SOC_VALUE_ENUM_SINGLE(PCM186X_ADC2_INPUT_SEL_R, 0, + PCM186X_ADC_INPUT_SEL_MASK, + ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text), + pcm186x_adcr_input_channel_sel_text, + pcm186x_adc_input_channel_sel_value), +}; + +static const struct snd_kcontrol_new pcm186x_adc_mux_controls[] = { + SOC_DAPM_ENUM("ADC1 Left Input", pcm186x_adc_input_channel_sel[0]), + SOC_DAPM_ENUM("ADC1 Right Input", pcm186x_adc_input_channel_sel[1]), + SOC_DAPM_ENUM("ADC2 Left Input", pcm186x_adc_input_channel_sel[2]), + SOC_DAPM_ENUM("ADC2 Right Input", pcm186x_adc_input_channel_sel[3]), +}; + +static const struct snd_soc_dapm_widget pcm1863_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("VINL1"), + SND_SOC_DAPM_INPUT("VINR1"), + SND_SOC_DAPM_INPUT("VINL2"), + SND_SOC_DAPM_INPUT("VINR2"), + SND_SOC_DAPM_INPUT("VINL3"), + SND_SOC_DAPM_INPUT("VINR3"), + SND_SOC_DAPM_INPUT("VINL4"), + SND_SOC_DAPM_INPUT("VINR4"), + + SND_SOC_DAPM_MUX("ADC Left Capture Source", SND_SOC_NOPM, 0, 0, + &pcm186x_adc_mux_controls[0]), + SND_SOC_DAPM_MUX("ADC Right Capture Source", SND_SOC_NOPM, 0, 0, + &pcm186x_adc_mux_controls[1]), + + /* + * Put the codec into SLEEP mode when not in use, allowing the + * Energysense mechanism to operate. + */ + SND_SOC_DAPM_ADC("ADC", "HiFi Capture", PCM186X_POWER_CTRL, 1, 0), +}; + +static const struct snd_soc_dapm_widget pcm1865_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("VINL1"), + SND_SOC_DAPM_INPUT("VINR1"), + SND_SOC_DAPM_INPUT("VINL2"), + SND_SOC_DAPM_INPUT("VINR2"), + SND_SOC_DAPM_INPUT("VINL3"), + SND_SOC_DAPM_INPUT("VINR3"), + SND_SOC_DAPM_INPUT("VINL4"), + SND_SOC_DAPM_INPUT("VINR4"), + + SND_SOC_DAPM_MUX("ADC1 Left Capture Source", SND_SOC_NOPM, 0, 0, + &pcm186x_adc_mux_controls[0]), + SND_SOC_DAPM_MUX("ADC1 Right Capture Source", SND_SOC_NOPM, 0, 0, + &pcm186x_adc_mux_controls[1]), + SND_SOC_DAPM_MUX("ADC2 Left Capture Source", SND_SOC_NOPM, 0, 0, + &pcm186x_adc_mux_controls[2]), + SND_SOC_DAPM_MUX("ADC2 Right Capture Source", SND_SOC_NOPM, 0, 0, + &pcm186x_adc_mux_controls[3]), + + /* + * Put the codec into SLEEP mode when not in use, allowing the + * Energysense mechanism to operate. + */ + SND_SOC_DAPM_ADC("ADC1", "HiFi Capture 1", PCM186X_POWER_CTRL, 1, 0), + SND_SOC_DAPM_ADC("ADC2", "HiFi Capture 2", PCM186X_POWER_CTRL, 1, 0), +}; + +static const struct snd_soc_dapm_route pcm1863_dapm_routes[] = { + { "ADC Left Capture Source", NULL, "VINL1" }, + { "ADC Left Capture Source", NULL, "VINR1" }, + { "ADC Left Capture Source", NULL, "VINL2" }, + { "ADC Left Capture Source", NULL, "VINR2" }, + { "ADC Left Capture Source", NULL, "VINL3" }, + { "ADC Left Capture Source", NULL, "VINR3" }, + { "ADC Left Capture Source", NULL, "VINL4" }, + { "ADC Left Capture Source", NULL, "VINR4" }, + + { "ADC", NULL, "ADC Left Capture Source" }, + + { "ADC Right Capture Source", NULL, "VINL1" }, + { "ADC Right Capture Source", NULL, "VINR1" }, + { "ADC Right Capture Source", NULL, "VINL2" }, + { "ADC Right Capture Source", NULL, "VINR2" }, + { "ADC Right Capture Source", NULL, "VINL3" }, + { "ADC Right Capture Source", NULL, "VINR3" }, + { "ADC Right Capture Source", NULL, "VINL4" }, + { "ADC Right Capture Source", NULL, "VINR4" }, + + { "ADC", NULL, "ADC Right Capture Source" }, +}; + +static const struct snd_soc_dapm_route pcm1865_dapm_routes[] = { + { "ADC1 Left Capture Source", NULL, "VINL1" }, + { "ADC1 Left Capture Source", NULL, "VINR1" }, + { "ADC1 Left Capture Source", NULL, "VINL2" }, + { "ADC1 Left Capture Source", NULL, "VINR2" }, + { "ADC1 Left Capture Source", NULL, "VINL3" }, + { "ADC1 Left Capture Source", NULL, "VINR3" }, + { "ADC1 Left Capture Source", NULL, "VINL4" }, + { "ADC1 Left Capture Source", NULL, "VINR4" }, + + { "ADC1", NULL, "ADC1 Left Capture Source" }, + + { "ADC1 Right Capture Source", NULL, "VINL1" }, + { "ADC1 Right Capture Source", NULL, "VINR1" }, + { "ADC1 Right Capture Source", NULL, "VINL2" }, + { "ADC1 Right Capture Source", NULL, "VINR2" }, + { "ADC1 Right Capture Source", NULL, "VINL3" }, + { "ADC1 Right Capture Source", NULL, "VINR3" }, + { "ADC1 Right Capture Source", NULL, "VINL4" }, + { "ADC1 Right Capture Source", NULL, "VINR4" }, + + { "ADC1", NULL, "ADC1 Right Capture Source" }, + + { "ADC2 Left Capture Source", NULL, "VINL1" }, + { "ADC2 Left Capture Source", NULL, "VINR1" }, + { "ADC2 Left Capture Source", NULL, "VINL2" }, + { "ADC2 Left Capture Source", NULL, "VINR2" }, + { "ADC2 Left Capture Source", NULL, "VINL3" }, + { "ADC2 Left Capture Source", NULL, "VINR3" }, + { "ADC2 Left Capture Source", NULL, "VINL4" }, + { "ADC2 Left Capture Source", NULL, "VINR4" }, + + { "ADC2", NULL, "ADC2 Left Capture Source" }, + + { "ADC2 Right Capture Source", NULL, "VINL1" }, + { "ADC2 Right Capture Source", NULL, "VINR1" }, + { "ADC2 Right Capture Source", NULL, "VINL2" }, + { "ADC2 Right Capture Source", NULL, "VINR2" }, + { "ADC2 Right Capture Source", NULL, "VINL3" }, + { "ADC2 Right Capture Source", NULL, "VINR3" }, + { "ADC2 Right Capture Source", NULL, "VINL4" }, + { "ADC2 Right Capture Source", NULL, "VINR4" }, + + { "ADC2", NULL, "ADC2 Right Capture Source" }, +}; + +static int pcm186x_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + + struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec); + unsigned int rate = params_rate(params); + unsigned int format = params_format(params); + unsigned int width = params_width(params); + unsigned int channels = params_channels(params); + unsigned int div_lrck; + unsigned int div_bck; + u8 tdm_tx_sel = 0; + u8 pcm_cfg = 0; + + dev_dbg(codec->dev, "%s() rate=%u format=0x%x width=%u channels=%u\n", + __func__, rate, format, width, channels); + + switch (width) { + case 16: + pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_16 << + PCM186X_PCM_CFG_RX_WLEN_SHIFT | + PCM186X_PCM_CFG_TX_WLEN_16 << + PCM186X_PCM_CFG_TX_WLEN_SHIFT; + break; + case 20: + pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_20 << + PCM186X_PCM_CFG_RX_WLEN_SHIFT | + PCM186X_PCM_CFG_TX_WLEN_20 << + PCM186X_PCM_CFG_TX_WLEN_SHIFT; + break; + case 24: + pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_24 << + PCM186X_PCM_CFG_RX_WLEN_SHIFT | + PCM186X_PCM_CFG_TX_WLEN_24 << + PCM186X_PCM_CFG_TX_WLEN_SHIFT; + break; + case 32: + pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_32 << + PCM186X_PCM_CFG_RX_WLEN_SHIFT | + PCM186X_PCM_CFG_TX_WLEN_32 << + PCM186X_PCM_CFG_TX_WLEN_SHIFT; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, PCM186X_PCM_CFG, + PCM186X_PCM_CFG_RX_WLEN_MASK | + PCM186X_PCM_CFG_TX_WLEN_MASK, + pcm_cfg); + + div_lrck = width * channels; + + if (priv->is_tdm_mode) { + /* Select TDM transmission data */ + switch (channels) { + case 2: + tdm_tx_sel = PCM186X_TDM_TX_SEL_2CH; + break; + case 4: + tdm_tx_sel = PCM186X_TDM_TX_SEL_4CH; + break; + case 6: + tdm_tx_sel = PCM186X_TDM_TX_SEL_6CH; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, PCM186X_TDM_TX_SEL, + PCM186X_TDM_TX_SEL_MASK, tdm_tx_sel); + + /* In DSP/TDM mode, the LRCLK divider must be 256 */ + div_lrck = 256; + + /* Configure 1/256 duty cycle for LRCK */ + snd_soc_update_bits(codec, PCM186X_PCM_CFG, + PCM186X_PCM_CFG_TDM_LRCK_MODE, + PCM186X_PCM_CFG_TDM_LRCK_MODE); + } + + /* Only configure clock dividers in master mode. */ + if (priv->is_master_mode) { + div_bck = priv->sysclk / (div_lrck * rate); + + dev_dbg(codec->dev, + "%s() master_clk=%u div_bck=%u div_lrck=%u\n", + __func__, priv->sysclk, div_bck, div_lrck); + + snd_soc_write(codec, PCM186X_BCK_DIV, div_bck - 1); + snd_soc_write(codec, PCM186X_LRK_DIV, div_lrck - 1); + } + + return 0; +} + +static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec); + u8 clk_ctrl = 0; + u8 pcm_cfg = 0; + + dev_dbg(codec->dev, "%s() format=0x%x\n", __func__, format); + + /* set master/slave audio interface */ + switch (format & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + if (!priv->sysclk) { + dev_err(codec->dev, "operating in master mode requires sysclock to be configured\n"); + return -EINVAL; + } + clk_ctrl |= PCM186X_CLK_CTRL_MST_MODE; + priv->is_master_mode = true; + break; + case SND_SOC_DAIFMT_CBS_CFS: + priv->is_master_mode = false; + break; + default: + dev_err(codec->dev, "Invalid DAI master/slave interface\n"); + return -EINVAL; + } + + /* set interface polarity */ + switch (format & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + default: + dev_err(codec->dev, "Inverted DAI clocks not supported\n"); + return -EINVAL; + } + + /* set interface format */ + switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + pcm_cfg = PCM186X_PCM_CFG_FMT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + pcm_cfg = PCM186X_PCM_CFG_FMT_LEFTJ; + break; + case SND_SOC_DAIFMT_DSP_A: + priv->tdm_offset += 1; + /* Fall through... DSP_A uses the same basic config as DSP_B + * except we need to shift the TDM output by one BCK cycle + */ + case SND_SOC_DAIFMT_DSP_B: + priv->is_tdm_mode = true; + pcm_cfg = PCM186X_PCM_CFG_FMT_TDM; + break; + default: + dev_err(codec->dev, "Invalid DAI format\n"); + return -EINVAL; + } + + snd_soc_update_bits(codec, PCM186X_CLK_CTRL, + PCM186X_CLK_CTRL_MST_MODE, clk_ctrl); + + snd_soc_write(codec, PCM186X_TDM_TX_OFFSET, priv->tdm_offset); + + snd_soc_update_bits(codec, PCM186X_PCM_CFG, + PCM186X_PCM_CFG_FMT_MASK, pcm_cfg); + + return 0; +} + +static int pcm186x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec); + unsigned int first_slot, last_slot, tdm_offset; + + dev_dbg(codec->dev, + "%s() tx_mask=0x%x rx_mask=0x%x slots=%d slot_width=%d\n", + __func__, tx_mask, rx_mask, slots, slot_width); + + if (!tx_mask) { + dev_err(codec->dev, "tdm tx mask must not be 0\n"); + return -EINVAL; + } + + first_slot = __ffs(tx_mask); + last_slot = __fls(tx_mask); + + if (last_slot - first_slot != hweight32(tx_mask) - 1) { + dev_err(codec->dev, "tdm tx mask must be contiguous\n"); + return -EINVAL; + } + + tdm_offset = first_slot * slot_width; + + if (tdm_offset > 255) { + dev_err(codec->dev, "tdm tx slot selection out of bounds\n"); + return -EINVAL; + } + + priv->tdm_offset = tdm_offset; + + return 0; +} + +static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s() clk_id=%d freq=%u dir=%d\n", + __func__, clk_id, freq, dir); + + priv->sysclk = freq; + + return 0; +} + +const struct snd_soc_dai_ops pcm186x_dai_ops = { + .set_sysclk = pcm186x_set_dai_sysclk, + .set_tdm_slot = pcm186x_set_tdm_slot, + .set_fmt = pcm186x_set_fmt, + .hw_params = pcm186x_hw_params, +}; + +static struct snd_soc_dai_driver pcm1863_dai = { + .name = "pcm1863-aif", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = PCM186X_RATES, + .formats = PCM186X_FORMATS, + }, + .ops = &pcm186x_dai_ops, +}; + +static struct snd_soc_dai_driver pcm1865_dai = { + .name = "pcm1865-aif", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 4, + .rates = PCM186X_RATES, + .formats = PCM186X_FORMATS, + }, + .ops = &pcm186x_dai_ops, +}; + +static int pcm186x_power_on(struct snd_soc_codec *codec) +{ + struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec); + int ret = 0; + + ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret) + return ret; + + regcache_cache_only(priv->regmap, false); + ret = regcache_sync(priv->regmap); + if (ret) { + dev_err(codec->dev, "Failed to restore cache\n"); + regcache_cache_only(priv->regmap, true); + regulator_bulk_disable(ARRAY_SIZE(priv->supplies), + priv->supplies); + return ret; + } + + snd_soc_update_bits(codec, PCM186X_POWER_CTRL, + PCM186X_PWR_CTRL_PWRDN, 0); + + return 0; +} + +static int pcm186x_power_off(struct snd_soc_codec *codec) +{ + struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec); + int ret; + + snd_soc_update_bits(codec, PCM186X_POWER_CTRL, + PCM186X_PWR_CTRL_PWRDN, PCM186X_PWR_CTRL_PWRDN); + + regcache_cache_only(priv->regmap, true); + + ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret) + return ret; + + return 0; +} + +static int pcm186x_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + dev_dbg(codec->dev, "## %s: %d -> %d\n", __func__, + snd_soc_codec_get_bias_level(codec), level); + + switch (level) { + case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) + pcm186x_power_on(codec); + break; + case SND_SOC_BIAS_OFF: + pcm186x_power_off(codec); + break; + } + + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_pcm1863 = { + .set_bias_level = pcm186x_set_bias_level, + + .component_driver = { + .controls = pcm1863_snd_controls, + .num_controls = ARRAY_SIZE(pcm1863_snd_controls), + .dapm_widgets = pcm1863_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pcm1863_dapm_widgets), + .dapm_routes = pcm1863_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(pcm1863_dapm_routes), + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_pcm1865 = { + .set_bias_level = pcm186x_set_bias_level, + .suspend_bias_off = true, + + .component_driver = { + .controls = pcm1865_snd_controls, + .num_controls = ARRAY_SIZE(pcm1865_snd_controls), + .dapm_widgets = pcm1865_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pcm1865_dapm_widgets), + .dapm_routes = pcm1865_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(pcm1865_dapm_routes), + }, +}; + +static bool pcm186x_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case PCM186X_PAGE: + case PCM186X_DEVICE_STATUS: + case PCM186X_FSAMPLE_STATUS: + case PCM186X_DIV_STATUS: + case PCM186X_CLK_STATUS: + case PCM186X_SUPPLY_STATUS: + case PCM186X_MMAP_STAT_CTRL: + case PCM186X_MMAP_ADDRESS: + return true; + } + + return false; +} + +static const struct regmap_range_cfg pcm186x_range = { + .name = "Pages", + .range_max = PCM186X_MAX_REGISTER, + .selector_reg = PCM186X_PAGE, + .selector_mask = 0xff, + .window_len = PCM186X_PAGE_LEN, +}; + +const struct regmap_config pcm186x_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .volatile_reg = pcm186x_volatile, + + .ranges = &pcm186x_range, + .num_ranges = 1, + + .max_register = PCM186X_MAX_REGISTER, + + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(pcm186x_regmap); + +int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq, + struct regmap *regmap) +{ + struct pcm186x_priv *priv; + int i, ret; + + priv = devm_kzalloc(dev, sizeof(struct pcm186x_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + priv->regmap = regmap; + + for (i = 0; i < ARRAY_SIZE(priv->supplies); i++) + priv->supplies[i].supply = pcm186x_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret) { + dev_err(dev, "failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret) { + dev_err(dev, "failed enable supplies: %d\n", ret); + return ret; + } + + /* Reset device registers for a consistent power-on like state */ + ret = regmap_write(regmap, PCM186X_PAGE, PCM186X_RESET); + if (ret) { + dev_err(dev, "failed to write device: %d\n", ret); + return ret; + } + + ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret) { + dev_err(dev, "failed disable supplies: %d\n", ret); + return ret; + } + + switch (type) { + case PCM1865: + case PCM1864: + ret = snd_soc_register_codec(dev, &soc_codec_dev_pcm1865, + &pcm1865_dai, 1); + break; + case PCM1863: + case PCM1862: + default: + ret = snd_soc_register_codec(dev, &soc_codec_dev_pcm1863, + &pcm1863_dai, 1); + } + if (ret) { + dev_err(dev, "failed to register CODEC: %d\n", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(pcm186x_probe); + +int pcm186x_remove(struct device *dev) +{ + snd_soc_unregister_codec(dev); + + return 0; +} +EXPORT_SYMBOL_GPL(pcm186x_remove); + +MODULE_AUTHOR("Andreas Dannenberg "); +MODULE_AUTHOR("Andrew F. Davis "); +MODULE_DESCRIPTION("PCM186x Universal Audio ADC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm186x.h b/sound/soc/codecs/pcm186x.h new file mode 100644 index 000000000000..b630111bb3c4 --- /dev/null +++ b/sound/soc/codecs/pcm186x.h @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Texas Instruments PCM186x Universal Audio ADC + * + * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com + * Andreas Dannenberg + * Andrew F. Davis + */ + +#ifndef _PCM186X_H_ +#define _PCM186X_H_ + +#include +#include + +enum pcm186x_type { + PCM1862, + PCM1863, + PCM1864, + PCM1865, +}; + +#define PCM186X_RATES SNDRV_PCM_RATE_8000_192000 +#define PCM186X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define PCM186X_PAGE_LEN 0x0100 +#define PCM186X_PAGE_BASE(n) (PCM186X_PAGE_LEN * n) + +/* The page selection register address is the same on all pages */ +#define PCM186X_PAGE 0 + +/* Register Definitions - Page 0 */ +#define PCM186X_PGA_VAL_CH1_L (PCM186X_PAGE_BASE(0) + 1) +#define PCM186X_PGA_VAL_CH1_R (PCM186X_PAGE_BASE(0) + 2) +#define PCM186X_PGA_VAL_CH2_L (PCM186X_PAGE_BASE(0) + 3) +#define PCM186X_PGA_VAL_CH2_R (PCM186X_PAGE_BASE(0) + 4) +#define PCM186X_PGA_CTRL (PCM186X_PAGE_BASE(0) + 5) +#define PCM186X_ADC1_INPUT_SEL_L (PCM186X_PAGE_BASE(0) + 6) +#define PCM186X_ADC1_INPUT_SEL_R (PCM186X_PAGE_BASE(0) + 7) +#define PCM186X_ADC2_INPUT_SEL_L (PCM186X_PAGE_BASE(0) + 8) +#define PCM186X_ADC2_INPUT_SEL_R (PCM186X_PAGE_BASE(0) + 9) +#define PCM186X_AUXADC_INPUT_SEL (PCM186X_PAGE_BASE(0) + 10) +#define PCM186X_PCM_CFG (PCM186X_PAGE_BASE(0) + 11) +#define PCM186X_TDM_TX_SEL (PCM186X_PAGE_BASE(0) + 12) +#define PCM186X_TDM_TX_OFFSET (PCM186X_PAGE_BASE(0) + 13) +#define PCM186X_TDM_RX_OFFSET (PCM186X_PAGE_BASE(0) + 14) +#define PCM186X_DPGA_VAL_CH1_L (PCM186X_PAGE_BASE(0) + 15) +#define PCM186X_GPIO1_0_CTRL (PCM186X_PAGE_BASE(0) + 16) +#define PCM186X_GPIO3_2_CTRL (PCM186X_PAGE_BASE(0) + 17) +#define PCM186X_GPIO1_0_DIR_CTRL (PCM186X_PAGE_BASE(0) + 18) +#define PCM186X_GPIO3_2_DIR_CTRL (PCM186X_PAGE_BASE(0) + 19) +#define PCM186X_GPIO_IN_OUT (PCM186X_PAGE_BASE(0) + 20) +#define PCM186X_GPIO_PULL_CTRL (PCM186X_PAGE_BASE(0) + 21) +#define PCM186X_DPGA_VAL_CH1_R (PCM186X_PAGE_BASE(0) + 22) +#define PCM186X_DPGA_VAL_CH2_L (PCM186X_PAGE_BASE(0) + 23) +#define PCM186X_DPGA_VAL_CH2_R (PCM186X_PAGE_BASE(0) + 24) +#define PCM186X_DPGA_GAIN_CTRL (PCM186X_PAGE_BASE(0) + 25) +#define PCM186X_DPGA_MIC_CTRL (PCM186X_PAGE_BASE(0) + 26) +#define PCM186X_DIN_RESAMP_CTRL (PCM186X_PAGE_BASE(0) + 27) +#define PCM186X_CLK_CTRL (PCM186X_PAGE_BASE(0) + 32) +#define PCM186X_DSP1_CLK_DIV (PCM186X_PAGE_BASE(0) + 33) +#define PCM186X_DSP2_CLK_DIV (PCM186X_PAGE_BASE(0) + 34) +#define PCM186X_ADC_CLK_DIV (PCM186X_PAGE_BASE(0) + 35) +#define PCM186X_PLL_SCK_DIV (PCM186X_PAGE_BASE(0) + 37) +#define PCM186X_BCK_DIV (PCM186X_PAGE_BASE(0) + 38) +#define PCM186X_LRK_DIV (PCM186X_PAGE_BASE(0) + 39) +#define PCM186X_PLL_CTRL (PCM186X_PAGE_BASE(0) + 40) +#define PCM186X_PLL_P_DIV (PCM186X_PAGE_BASE(0) + 41) +#define PCM186X_PLL_R_DIV (PCM186X_PAGE_BASE(0) + 42) +#define PCM186X_PLL_J_DIV (PCM186X_PAGE_BASE(0) + 43) +#define PCM186X_PLL_D_DIV_LSB (PCM186X_PAGE_BASE(0) + 44) +#define PCM186X_PLL_D_DIV_MSB (PCM186X_PAGE_BASE(0) + 45) +#define PCM186X_SIGDET_MODE (PCM186X_PAGE_BASE(0) + 48) +#define PCM186X_SIGDET_MASK (PCM186X_PAGE_BASE(0) + 49) +#define PCM186X_SIGDET_STAT (PCM186X_PAGE_BASE(0) + 50) +#define PCM186X_SIGDET_LOSS_TIME (PCM186X_PAGE_BASE(0) + 52) +#define PCM186X_SIGDET_SCAN_TIME (PCM186X_PAGE_BASE(0) + 53) +#define PCM186X_SIGDET_INT_INTVL (PCM186X_PAGE_BASE(0) + 54) +#define PCM186X_SIGDET_DC_REF_CH1_L (PCM186X_PAGE_BASE(0) + 64) +#define PCM186X_SIGDET_DC_DIFF_CH1_L (PCM186X_PAGE_BASE(0) + 65) +#define PCM186X_SIGDET_DC_LEV_CH1_L (PCM186X_PAGE_BASE(0) + 66) +#define PCM186X_SIGDET_DC_REF_CH1_R (PCM186X_PAGE_BASE(0) + 67) +#define PCM186X_SIGDET_DC_DIFF_CH1_R (PCM186X_PAGE_BASE(0) + 68) +#define PCM186X_SIGDET_DC_LEV_CH1_R (PCM186X_PAGE_BASE(0) + 69) +#define PCM186X_SIGDET_DC_REF_CH2_L (PCM186X_PAGE_BASE(0) + 70) +#define PCM186X_SIGDET_DC_DIFF_CH2_L (PCM186X_PAGE_BASE(0) + 71) +#define PCM186X_SIGDET_DC_LEV_CH2_L (PCM186X_PAGE_BASE(0) + 72) +#define PCM186X_SIGDET_DC_REF_CH2_R (PCM186X_PAGE_BASE(0) + 73) +#define PCM186X_SIGDET_DC_DIFF_CH2_R (PCM186X_PAGE_BASE(0) + 74) +#define PCM186X_SIGDET_DC_LEV_CH2_R (PCM186X_PAGE_BASE(0) + 75) +#define PCM186X_SIGDET_DC_REF_CH3_L (PCM186X_PAGE_BASE(0) + 76) +#define PCM186X_SIGDET_DC_DIFF_CH3_L (PCM186X_PAGE_BASE(0) + 77) +#define PCM186X_SIGDET_DC_LEV_CH3_L (PCM186X_PAGE_BASE(0) + 78) +#define PCM186X_SIGDET_DC_REF_CH3_R (PCM186X_PAGE_BASE(0) + 79) +#define PCM186X_SIGDET_DC_DIFF_CH3_R (PCM186X_PAGE_BASE(0) + 80) +#define PCM186X_SIGDET_DC_LEV_CH3_R (PCM186X_PAGE_BASE(0) + 81) +#define PCM186X_SIGDET_DC_REF_CH4_L (PCM186X_PAGE_BASE(0) + 82) +#define PCM186X_SIGDET_DC_DIFF_CH4_L (PCM186X_PAGE_BASE(0) + 83) +#define PCM186X_SIGDET_DC_LEV_CH4_L (PCM186X_PAGE_BASE(0) + 84) +#define PCM186X_SIGDET_DC_REF_CH4_R (PCM186X_PAGE_BASE(0) + 85) +#define PCM186X_SIGDET_DC_DIFF_CH4_R (PCM186X_PAGE_BASE(0) + 86) +#define PCM186X_SIGDET_DC_LEV_CH4_R (PCM186X_PAGE_BASE(0) + 87) +#define PCM186X_AUXADC_DATA_CTRL (PCM186X_PAGE_BASE(0) + 88) +#define PCM186X_AUXADC_DATA_LSB (PCM186X_PAGE_BASE(0) + 89) +#define PCM186X_AUXADC_DATA_MSB (PCM186X_PAGE_BASE(0) + 90) +#define PCM186X_INT_ENABLE (PCM186X_PAGE_BASE(0) + 96) +#define PCM186X_INT_FLAG (PCM186X_PAGE_BASE(0) + 97) +#define PCM186X_INT_POL_WIDTH (PCM186X_PAGE_BASE(0) + 98) +#define PCM186X_POWER_CTRL (PCM186X_PAGE_BASE(0) + 112) +#define PCM186X_FILTER_MUTE_CTRL (PCM186X_PAGE_BASE(0) + 113) +#define PCM186X_DEVICE_STATUS (PCM186X_PAGE_BASE(0) + 114) +#define PCM186X_FSAMPLE_STATUS (PCM186X_PAGE_BASE(0) + 115) +#define PCM186X_DIV_STATUS (PCM186X_PAGE_BASE(0) + 116) +#define PCM186X_CLK_STATUS (PCM186X_PAGE_BASE(0) + 117) +#define PCM186X_SUPPLY_STATUS (PCM186X_PAGE_BASE(0) + 120) + +/* Register Definitions - Page 1 */ +#define PCM186X_MMAP_STAT_CTRL (PCM186X_PAGE_BASE(1) + 1) +#define PCM186X_MMAP_ADDRESS (PCM186X_PAGE_BASE(1) + 2) +#define PCM186X_MEM_WDATA0 (PCM186X_PAGE_BASE(1) + 4) +#define PCM186X_MEM_WDATA1 (PCM186X_PAGE_BASE(1) + 5) +#define PCM186X_MEM_WDATA2 (PCM186X_PAGE_BASE(1) + 6) +#define PCM186X_MEM_WDATA3 (PCM186X_PAGE_BASE(1) + 7) +#define PCM186X_MEM_RDATA0 (PCM186X_PAGE_BASE(1) + 8) +#define PCM186X_MEM_RDATA1 (PCM186X_PAGE_BASE(1) + 9) +#define PCM186X_MEM_RDATA2 (PCM186X_PAGE_BASE(1) + 10) +#define PCM186X_MEM_RDATA3 (PCM186X_PAGE_BASE(1) + 11) + +/* Register Definitions - Page 3 */ +#define PCM186X_OSC_PWR_DOWN_CTRL (PCM186X_PAGE_BASE(3) + 18) +#define PCM186X_MIC_BIAS_CTRL (PCM186X_PAGE_BASE(3) + 21) + +/* Register Definitions - Page 253 */ +#define PCM186X_CURR_TRIM_CTRL (PCM186X_PAGE_BASE(253) + 20) + +#define PCM186X_MAX_REGISTER PCM186X_CURR_TRIM_CTRL + +/* PCM186X_PAGE */ +#define PCM186X_RESET 0xff + +/* PCM186X_ADCX_INPUT_SEL_X */ +#define PCM186X_ADC_INPUT_SEL_POL BIT(7) +#define PCM186X_ADC_INPUT_SEL_MASK GENMASK(5, 0) + +/* PCM186X_PCM_CFG */ +#define PCM186X_PCM_CFG_RX_WLEN_MASK GENMASK(7, 6) +#define PCM186X_PCM_CFG_RX_WLEN_SHIFT 6 +#define PCM186X_PCM_CFG_RX_WLEN_32 0x00 +#define PCM186X_PCM_CFG_RX_WLEN_24 0x01 +#define PCM186X_PCM_CFG_RX_WLEN_20 0x02 +#define PCM186X_PCM_CFG_RX_WLEN_16 0x03 +#define PCM186X_PCM_CFG_TDM_LRCK_MODE BIT(4) +#define PCM186X_PCM_CFG_TX_WLEN_MASK GENMASK(3, 2) +#define PCM186X_PCM_CFG_TX_WLEN_SHIFT 2 +#define PCM186X_PCM_CFG_TX_WLEN_32 0x00 +#define PCM186X_PCM_CFG_TX_WLEN_24 0x01 +#define PCM186X_PCM_CFG_TX_WLEN_20 0x02 +#define PCM186X_PCM_CFG_TX_WLEN_16 0x03 +#define PCM186X_PCM_CFG_FMT_MASK GENMASK(1, 0) +#define PCM186X_PCM_CFG_FMT_SHIFT 0 +#define PCM186X_PCM_CFG_FMT_I2S 0x00 +#define PCM186X_PCM_CFG_FMT_LEFTJ 0x01 +#define PCM186X_PCM_CFG_FMT_RIGHTJ 0x02 +#define PCM186X_PCM_CFG_FMT_TDM 0x03 + +/* PCM186X_TDM_TX_SEL */ +#define PCM186X_TDM_TX_SEL_2CH 0x00 +#define PCM186X_TDM_TX_SEL_4CH 0x01 +#define PCM186X_TDM_TX_SEL_6CH 0x02 +#define PCM186X_TDM_TX_SEL_MASK 0x03 + +/* PCM186X_CLK_CTRL */ +#define PCM186X_CLK_CTRL_SCK_XI_SEL1 BIT(7) +#define PCM186X_CLK_CTRL_SCK_XI_SEL0 BIT(6) +#define PCM186X_CLK_CTRL_SCK_SRC_PLL BIT(5) +#define PCM186X_CLK_CTRL_MST_MODE BIT(4) +#define PCM186X_CLK_CTRL_ADC_SRC_PLL BIT(3) +#define PCM186X_CLK_CTRL_DSP2_SRC_PLL BIT(2) +#define PCM186X_CLK_CTRL_DSP1_SRC_PLL BIT(1) +#define PCM186X_CLK_CTRL_CLKDET_EN BIT(0) + +/* PCM186X_PLL_CTRL */ +#define PCM186X_PLL_CTRL_LOCK BIT(4) +#define PCM186X_PLL_CTRL_REF_SEL BIT(1) +#define PCM186X_PLL_CTRL_EN BIT(0) + +/* PCM186X_POWER_CTRL */ +#define PCM186X_PWR_CTRL_PWRDN BIT(2) +#define PCM186X_PWR_CTRL_SLEEP BIT(1) +#define PCM186X_PWR_CTRL_STBY BIT(0) + +/* PCM186X_CLK_STATUS */ +#define PCM186X_CLK_STATUS_LRCKHLT BIT(6) +#define PCM186X_CLK_STATUS_BCKHLT BIT(5) +#define PCM186X_CLK_STATUS_SCKHLT BIT(4) +#define PCM186X_CLK_STATUS_LRCKERR BIT(2) +#define PCM186X_CLK_STATUS_BCKERR BIT(1) +#define PCM186X_CLK_STATUS_SCKERR BIT(0) + +/* PCM186X_SUPPLY_STATUS */ +#define PCM186X_SUPPLY_STATUS_DVDD BIT(2) +#define PCM186X_SUPPLY_STATUS_AVDD BIT(1) +#define PCM186X_SUPPLY_STATUS_LDO BIT(0) + +/* PCM186X_MMAP_STAT_CTRL */ +#define PCM186X_MMAP_STAT_DONE BIT(4) +#define PCM186X_MMAP_STAT_BUSY BIT(2) +#define PCM186X_MMAP_STAT_R_REQ BIT(1) +#define PCM186X_MMAP_STAT_W_REQ BIT(0) + +extern const struct regmap_config pcm186x_regmap; + +int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq, + struct regmap *regmap); +int pcm186x_remove(struct device *dev); + +#endif /* _PCM186X_H_ */ -- cgit v1.2.3 From eb2a8168b9fd69f66199d9d7e86d23fecfab4e33 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 5 Dec 2017 14:52:55 -0600 Subject: ASoC: pcm186x: Add PCM186x binding documentation Add the dt-binding documentation for the TI PCM186x 2ch and 4ch Audio ADCs With Universal Front End. Signed-off-by: Andrew F. Davis Acked-by: Rob Herring Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/pcm186x.txt | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/pcm186x.txt diff --git a/Documentation/devicetree/bindings/sound/pcm186x.txt b/Documentation/devicetree/bindings/sound/pcm186x.txt new file mode 100644 index 000000000000..1087f4855980 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/pcm186x.txt @@ -0,0 +1,42 @@ +Texas Instruments PCM186x Universal Audio ADC + +These devices support both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "ti,pcm1862", + "ti,pcm1863", + "ti,pcm1864", + "ti,pcm1865" + + - reg : The I2C address of the device for I2C, the chip select + number for SPI. + + - avdd-supply: Analog core power supply (3.3v) + - dvdd-supply: Digital core power supply + - iovdd-supply: Digital IO power supply + See regulator/regulator.txt for more information + +CODEC input pins: + * VINL1 + * VINR1 + * VINL2 + * VINR2 + * VINL3 + * VINR3 + * VINL4 + * VINR4 + +The pins can be used in referring sound node's audio-routing property. + +Example: + + pcm186x: audio-codec@4a { + compatible = "ti,pcm1865"; + reg = <0x4a>; + + avdd-supply = <®_3v3_analog>; + dvdd-supply = <®_3v3>; + iovdd-supply = <®_1v8>; + }; -- cgit v1.2.3 From d1b726a9018e3f684ce190a1cbe012cb64f363d8 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 6 Dec 2017 16:17:27 +0100 Subject: ASoC: fsl_asrc: protect macro argument Protect macro argument with parentheses to avoid ambiguity. This fixes a warning seen with clang: warning: logical not is only applied to the left hand side of this comparison Signed-off-by: Stefan Agner Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h index 0f163abe4ba3..ec33dab4b909 100644 --- a/sound/soc/fsl/fsl_asrc.h +++ b/sound/soc/fsl/fsl_asrc.h @@ -57,7 +57,7 @@ #define REG_ASRDOC 0x74 #define REG_ASRDI(i) (REG_ASRDIA + (i << 3)) #define REG_ASRDO(i) (REG_ASRDOA + (i << 3)) -#define REG_ASRDx(x, i) (x == IN ? REG_ASRDI(i) : REG_ASRDO(i)) +#define REG_ASRDx(x, i) ((x) == IN ? REG_ASRDI(i) : REG_ASRDO(i)) #define REG_ASRIDRHA 0x80 #define REG_ASRIDRLA 0x84 -- cgit v1.2.3 From b2ca3bdd07f68ca63fdb8e45f1fe039ba6af54a2 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Wed, 6 Dec 2017 16:34:01 +0530 Subject: ASoC: Intel: Skylake: Remove second shim read in register_poll No need to read the register again if the value read has already matched the target during the loop. So remove the second shim read. Signed-off-by: Subhransu S. Prusty Signed-off-by: Guneshwor Singh Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-dsp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c index 11c0805393ff..fd82f4b1d4a0 100644 --- a/sound/soc/intel/common/sst-dsp.c +++ b/sound/soc/intel/common/sst-dsp.c @@ -269,7 +269,7 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, */ timeout = jiffies + msecs_to_jiffies(time); - while (((sst_dsp_shim_read_unlocked(ctx, offset) & mask) != target) + while ((((reg = sst_dsp_shim_read_unlocked(ctx, offset)) & mask) != target) && time_before(jiffies, timeout)) { k++; if (k > 10) @@ -278,8 +278,6 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, usleep_range(s, 2*s); } - reg = sst_dsp_shim_read_unlocked(ctx, offset); - if ((reg & mask) == target) { dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n", reg, operation); -- cgit v1.2.3 From 437623554e89f388648a31c35e1e5e4c7cb09004 Mon Sep 17 00:00:00 2001 From: Pradeep Tewani Date: Wed, 6 Dec 2017 16:34:02 +0530 Subject: ASoC: Intel: Skylake: Parse vendor tokens to build A-State table A-State table is a power management table which allows the driver to configure the DSP clock source corresponding to various load thresholds. The table contains upto 3 A-State entries. The patch adds and parses the corresponding A-State tokens to build the table. Signed-off-by: Pradeep Tewani Signed-off-by: Guneshwor Singh Acked-By: Vinod Koul Signed-off-by: Mark Brown --- include/uapi/sound/snd_sst_tokens.h | 17 ++++++++++++- sound/soc/intel/skylake/skl-topology.c | 44 +++++++++++++++++++++++++++++++++- sound/soc/intel/skylake/skl.h | 17 +++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/include/uapi/sound/snd_sst_tokens.h b/include/uapi/sound/snd_sst_tokens.h index f691e421f5e8..9e38fea11b2b 100644 --- a/include/uapi/sound/snd_sst_tokens.h +++ b/include/uapi/sound/snd_sst_tokens.h @@ -221,6 +221,17 @@ * %SKL_TKN_MM_U32_NUM_IN_FMT: Number of input formats * %SKL_TKN_MM_U32_NUM_OUT_FMT: Number of output formats * + * %SKL_TKN_U32_ASTATE_IDX: Table Index for the A-State entry to be filled + * with kcps and clock source + * + * %SKL_TKN_U32_ASTATE_COUNT: Number of valid entries in A-State table + * + * %SKL_TKN_U32_ASTATE_KCPS: Specifies the core load threshold (in kilo + * cycles per second) below which DSP is clocked + * from source specified by clock source. + * + * %SKL_TKN_U32_ASTATE_CLK_SRC: Clock source for A-State entry + * * module_id and loadable flags dont have tokens as these values will be * read from the DSP FW manifest * @@ -308,7 +319,11 @@ enum SKL_TKNS { SKL_TKN_MM_U32_NUM_IN_FMT, SKL_TKN_MM_U32_NUM_OUT_FMT, - SKL_TKN_MAX = SKL_TKN_MM_U32_NUM_OUT_FMT, + SKL_TKN_U32_ASTATE_IDX, + SKL_TKN_U32_ASTATE_COUNT, + SKL_TKN_U32_ASTATE_KCPS, + SKL_TKN_U32_ASTATE_CLK_SRC, + SKL_TKN_MAX = SKL_TKN_U32_ASTATE_CLK_SRC, }; #endif diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 1200b7c6af56..d8d110b3be01 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -3037,11 +3037,13 @@ static int skl_tplg_get_int_tkn(struct device *dev, struct snd_soc_tplg_vendor_value_elem *tkn_elem, struct skl *skl) { - int tkn_count = 0, ret; + int tkn_count = 0, ret, size; static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx; struct skl_module_res *res = NULL; struct skl_module_iface *fmt = NULL; struct skl_module *mod = NULL; + static struct skl_astate_param *astate_table; + static int astate_cfg_idx, count; int i; if (skl->modules) { @@ -3074,6 +3076,46 @@ static int skl_tplg_get_int_tkn(struct device *dev, mod_idx = tkn_elem->value; break; + case SKL_TKN_U32_ASTATE_COUNT: + if (astate_table != NULL) { + dev_err(dev, "More than one entry for A-State count"); + return -EINVAL; + } + + if (tkn_elem->value > SKL_MAX_ASTATE_CFG) { + dev_err(dev, "Invalid A-State count %d\n", + tkn_elem->value); + return -EINVAL; + } + + size = tkn_elem->value * sizeof(struct skl_astate_param) + + sizeof(count); + skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL); + if (!skl->cfg.astate_cfg) + return -ENOMEM; + + astate_table = skl->cfg.astate_cfg->astate_table; + count = skl->cfg.astate_cfg->count = tkn_elem->value; + break; + + case SKL_TKN_U32_ASTATE_IDX: + if (tkn_elem->value >= count) { + dev_err(dev, "Invalid A-State index %d\n", + tkn_elem->value); + return -EINVAL; + } + + astate_cfg_idx = tkn_elem->value; + break; + + case SKL_TKN_U32_ASTATE_KCPS: + astate_table[astate_cfg_idx].kcps = tkn_elem->value; + break; + + case SKL_TKN_U32_ASTATE_CLK_SRC: + astate_table[astate_cfg_idx].clk_src = tkn_elem->value; + break; + case SKL_TKN_U8_IN_PIN_TYPE: case SKL_TKN_U8_OUT_PIN_TYPE: case SKL_TKN_U8_IN_QUEUE_COUNT: diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 554ad6b5a823..46dda88ba139 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -29,6 +29,8 @@ #define SKL_SUSPEND_DELAY 2000 +#define SKL_MAX_ASTATE_CFG 3 + #define AZX_PCIREG_PGCTL 0x44 #define AZX_PGCTL_LSRMD_MASK (1 << 4) #define AZX_PCIREG_CGCTL 0x48 @@ -46,6 +48,20 @@ struct skl_dsp_resource { struct skl_debug; +struct skl_astate_param { + u32 kcps; + u32 clk_src; +}; + +struct skl_astate_config { + u32 count; + struct skl_astate_param astate_table[0]; +}; + +struct skl_fw_config { + struct skl_astate_config *astate_cfg; +}; + struct skl { struct hdac_ext_bus ebus; struct pci_dev *pci; @@ -77,6 +93,7 @@ struct skl { u8 nr_modules; struct skl_module **modules; bool use_tplg_pcm; + struct skl_fw_config cfg; }; #define skl_to_ebus(s) (&(s)->ebus) -- cgit v1.2.3 From 9452314d92d600e8702533b10f10ec440aad5db9 Mon Sep 17 00:00:00 2001 From: Pradeep Tewani Date: Wed, 6 Dec 2017 16:34:03 +0530 Subject: ASoC: Intel: Skylake: Configure DSP clock source DSP clock source is configured by sending the A-State table to the FW. Add the large config set IPC to configure the desired clock source Signed-off-by: Pradeep Tewani Signed-off-by: Guneshwor Singh Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 18 ++++++++++++++++++ sound/soc/intel/skylake/skl-pcm.c | 6 ++++++ sound/soc/intel/skylake/skl-sst-dsp.h | 3 +++ 3 files changed, 27 insertions(+) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index f637829833e6..4e63213a8d55 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -55,6 +55,19 @@ static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab) return 0; } +#define SKL_ASTATE_PARAM_ID 4 + +void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data) +{ + struct skl_ipc_large_config_msg msg = {0}; + + msg.large_param_id = SKL_ASTATE_PARAM_ID; + msg.param_data_size = (cnt * sizeof(struct skl_astate_param) + + sizeof(cnt)); + + skl_ipc_set_large_config(&ctx->ipc, &msg, data); +} + #define NOTIFICATION_PARAM_ID 3 #define NOTIFICATION_MASK 0xf @@ -409,6 +422,11 @@ int skl_resume_dsp(struct skl *skl) return ret; skl_dsp_enable_notification(skl->skl_sst, false); + + if (skl->cfg.astate_cfg != NULL) { + skl_dsp_set_astate_cfg(skl->skl_sst, skl->cfg.astate_cfg->count, + skl->cfg.astate_cfg); + } return ret; } diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 18138dc872d9..cc6535ab84d1 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1350,6 +1350,12 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform) skl_populate_modules(skl); skl->skl_sst->update_d0i3c = skl_update_d0i3c; skl_dsp_enable_notification(skl->skl_sst, false); + + if (skl->cfg.astate_cfg != NULL) { + skl_dsp_set_astate_cfg(skl->skl_sst, + skl->cfg.astate_cfg->count, + skl->cfg.astate_cfg); + } } pm_runtime_mark_last_busy(platform->dev); pm_runtime_put_autosuspend(platform->dev); diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index eba20d37ba8c..b8e799ed65ef 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -251,6 +251,9 @@ void skl_freeup_uuid_list(struct skl_sst *ctx); int skl_dsp_strip_extended_manifest(struct firmware *fw); void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable); + +void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data); + int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp, struct sst_dsp_device *skl_dev); -- cgit v1.2.3 From 0fb02ba36d01a04dab03c0a424607844ef4dadbf Mon Sep 17 00:00:00 2001 From: Puneeth Prabhu Date: Wed, 6 Dec 2017 16:34:05 +0530 Subject: ASoC: hdac_hdmi: Refresh sysfs during hdmi device probe All nodes of hdmi codec widgets are not updated in sysfs interface (/sys/bus/hdaudio/devices//widgets/) as the vendor widget is not programmed to enable all the converters and pins during init. So, refresh the sysfs widget interface after enabling all pins and converters. Signed-off-by: Puneeth Prabhu Signed-off-by: Subhransu S. Prusty Signed-off-by: Guneshwor Singh Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 3a35ede7027d..b706547c46d5 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2042,6 +2042,7 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) "Failed in parse and map nid with err: %d\n", ret); return ret; } + snd_hdac_refresh_widgets(hdev, true); /* ASoC specific initialization */ ret = snd_soc_register_codec(&hdev->dev, &hdmi_hda_codec, -- cgit v1.2.3 From 45a6008bfcdc3e620dcf1b2330766345097afe9c Mon Sep 17 00:00:00 2001 From: Puneeth Prabhu Date: Wed, 6 Dec 2017 16:34:06 +0530 Subject: ASoC: hdac_hdmi: Remove redundant assignments Assignments for start_nid, end_nid and num_nodes of hdac_device structure are already done in init. So, remove the redundant assignments. Signed-off-by: Puneeth Prabhu Signed-off-by: Guneshwor Singh Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index b706547c46d5..68a4a6b4e68e 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1465,10 +1465,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev, return -EINVAL; } - hdev->num_nodes = num_nodes; - hdev->start_nid = nid; - - for (i = 0; i < hdev->num_nodes; i++, nid++) { + for (i = 0; i < num_nodes; i++, nid++) { unsigned int caps; unsigned int type; @@ -1494,8 +1491,6 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev, } } - hdev->end_nid = nid; - if (!hdmi->num_pin || !hdmi->num_cvt) { ret = -EIO; goto free_widgets; -- cgit v1.2.3 From 769e40f0c17df53bac8999939993a280c1ea3dbd Mon Sep 17 00:00:00 2001 From: Pravin Shedge Date: Wed, 6 Dec 2017 23:09:00 +0530 Subject: ASoC: hisilicon: remove duplicate includes These duplicate includes have been found with scripts/checkincludes.pl but they have been removed manually to avoid removing false positives. Signed-off-by: Pravin Shedge Signed-off-by: Mark Brown --- sound/soc/hisilicon/hi6210-i2s.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c index 0c8f86d4020e..07a57209e055 100644 --- a/sound/soc/hisilicon/hi6210-i2s.c +++ b/sound/soc/hisilicon/hi6210-i2s.c @@ -36,7 +36,6 @@ #include #include #include -#include #include "hi6210-i2s.h" -- cgit v1.2.3 From dce231a484f72983cd7d5832aed4da04870a4d47 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 7 Dec 2017 14:11:32 +0000 Subject: ASoC: pcm186x: make pcm186x_dai_ops and pcm186x_adc_input_channel_sel_value static pcm186x_dai_ops and pcm186x_adc_input_channel_sel_value are local to the source and do not need to be in global scope, so make them static. Cleans up sparse warnings: symbol 'pcm186x_dai_ops' was not declared. Should it be static? symbol 'pcm186x_adc_input_channel_sel_value' was not declared. Should it be static? Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/codecs/pcm186x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c index f7aa56e20169..cdb51427facc 100644 --- a/sound/soc/codecs/pcm186x.c +++ b/sound/soc/codecs/pcm186x.c @@ -59,7 +59,7 @@ static const struct snd_kcontrol_new pcm1865_snd_controls[] = { pcm186x_pga_tlv), }; -const unsigned int pcm186x_adc_input_channel_sel_value[] = { +static const unsigned int pcm186x_adc_input_channel_sel_value[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x20, 0x30 @@ -475,7 +475,7 @@ static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, return 0; } -const struct snd_soc_dai_ops pcm186x_dai_ops = { +static const struct snd_soc_dai_ops pcm186x_dai_ops = { .set_sysclk = pcm186x_set_dai_sysclk, .set_tdm_slot = pcm186x_set_tdm_slot, .set_fmt = pcm186x_set_fmt, -- cgit v1.2.3 From 283c35062f778fc40f8eb5dc004ca37a7208ea66 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Thu, 7 Dec 2017 09:38:51 -0600 Subject: ASoC: tlv320aic31xx: Fix GPIO header includes Use of gpiod_* needs , add this here. Fixes: b6b247cd5e37 ("ASoC: tlv320aic31xx: Switch GPIO handling to use gpiod_* API") Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 38fd6ea275fb..13471a900085 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From cd15da88c358e9987a3b16bc821c980dd2377776 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Thu, 7 Dec 2017 09:38:52 -0600 Subject: ASoC: tlv320aic31xx: Use fwnode APIs over raw OF calls Use fwnode_* API instead of of_*, the results are the same but fwnode_* is cleaner and we get ACPI support. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 77 +++++++++++++++------------------------- 1 file changed, 29 insertions(+), 48 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 13471a900085..655c99db2426 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -157,7 +157,9 @@ struct aic31xx_priv { u8 i2c_regs_status; struct device *dev; struct regmap *regmap; + enum aic31xx_type codec_type; struct gpio_desc *gpio_reset; + int micbias_vg; struct aic31xx_pdata pdata; struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES]; @@ -450,7 +452,7 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, /* change mic bias voltage to user defined */ snd_soc_update_bits(codec, AIC31XX_MICBIAS, AIC31XX_MICBIAS_MASK, - aic31xx->pdata.micbias_vg << + aic31xx->micbias_vg << AIC31XX_MICBIAS_SHIFT); dev_dbg(codec->dev, "%s: turned on\n", __func__); break; @@ -673,14 +675,14 @@ static int aic31xx_add_controls(struct snd_soc_codec *codec) int ret = 0; struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); - if (!(aic31xx->pdata.codec_type & DAC31XX_BIT)) + if (!(aic31xx->codec_type & DAC31XX_BIT)) ret = snd_soc_add_codec_controls( codec, aic31xx_snd_controls, ARRAY_SIZE(aic31xx_snd_controls)); if (ret) return ret; - if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) + if (aic31xx->codec_type & AIC31XX_STEREO_CLASS_D_BIT) ret = snd_soc_add_codec_controls( codec, aic311x_snd_controls, ARRAY_SIZE(aic311x_snd_controls)); @@ -698,7 +700,7 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec) struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); int ret = 0; - if (aic31xx->pdata.codec_type & DAC31XX_BIT) { + if (aic31xx->codec_type & DAC31XX_BIT) { ret = snd_soc_dapm_new_controls( dapm, dac31xx_dapm_widgets, ARRAY_SIZE(dac31xx_dapm_widgets)); @@ -722,7 +724,7 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec) return ret; } - if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) { + if (aic31xx->codec_type & AIC31XX_STEREO_CLASS_D_BIT) { ret = snd_soc_dapm_new_controls( dapm, aic311x_dapm_widgets, ARRAY_SIZE(aic311x_dapm_widgets)); @@ -1279,42 +1281,6 @@ static const struct of_device_id tlv320aic31xx_of_match[] = { {}, }; MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match); - -static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx) -{ - struct device_node *np = aic31xx->dev->of_node; - unsigned int value = MICBIAS_2_0V; - int ret; - - of_property_read_u32(np, "ai31xx-micbias-vg", &value); - switch (value) { - case MICBIAS_2_0V: - case MICBIAS_2_5V: - case MICBIAS_AVDDV: - aic31xx->pdata.micbias_vg = value; - break; - default: - dev_err(aic31xx->dev, - "Bad ai31xx-micbias-vg value %d DT\n", - value); - aic31xx->pdata.micbias_vg = MICBIAS_2_0V; - } - - ret = of_get_named_gpio(np, "reset-gpios", 0); - if (ret > 0) { - aic31xx->pdata.gpio_reset = ret; - } else { - ret = of_get_named_gpio(np, "gpio-reset", 0); - if (ret > 0) { - dev_warn(aic31xx->dev, "Using deprecated property \"gpio-reset\", please update your DT"); - aic31xx->pdata.gpio_reset = ret; - } - } -} -#else /* CONFIG_OF */ -static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx) -{ -} #endif /* CONFIG_OF */ #ifdef CONFIG_ACPI @@ -1329,6 +1295,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct aic31xx_priv *aic31xx; + unsigned int micbias_value = MICBIAS_2_0V; int i, ret; dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__, @@ -1347,15 +1314,29 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, } aic31xx->dev = &i2c->dev; - aic31xx->pdata.codec_type = id->driver_data; + aic31xx->codec_type = id->driver_data; dev_set_drvdata(aic31xx->dev, aic31xx); - if (dev_get_platdata(aic31xx->dev)) - memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev), - sizeof(aic31xx->pdata)); - else if (aic31xx->dev->of_node) - aic31xx_pdata_from_of(aic31xx); + fwnode_property_read_u32(aic31xx->dev->fwnode, "ai31xx-micbias-vg", + &micbias_value); + switch (micbias_value) { + case MICBIAS_2_0V: + case MICBIAS_2_5V: + case MICBIAS_AVDDV: + aic31xx->micbias_vg = micbias_value; + break; + default: + dev_err(aic31xx->dev, "Bad ai31xx-micbias-vg value %d\n", + micbias_value); + aic31xx->micbias_vg = MICBIAS_2_0V; + } + + if (dev_get_platdata(aic31xx->dev)) { + memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev), sizeof(aic31xx->pdata)); + aic31xx->codec_type = aic31xx->pdata.codec_type; + aic31xx->micbias_vg = aic31xx->pdata.micbias_vg; + } aic31xx->gpio_reset = devm_gpiod_get_optional(aic31xx->dev, "reset", GPIOD_OUT_LOW); @@ -1375,7 +1356,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, return ret; } - if (aic31xx->pdata.codec_type & DAC31XX_BIT) + if (aic31xx->codec_type & DAC31XX_BIT) return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx, dac31xx_dai_driver, -- cgit v1.2.3 From 0ce918c9e070bf4fd17af0d76096ad184815bd79 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Thu, 7 Dec 2017 09:38:56 -0600 Subject: ASoC: tlv320aic31xx: Reset registers during power up Add a reset function that toggles the reset line if available or uses the software reset command otherwise. Use this in power up to ensure the registers are in a sane state. This is useful when the driver module is reloaded, or after Kexec, warm-reboots, etc.. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 655c99db2426..858cb8be445f 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1055,6 +1055,22 @@ static int aic31xx_regulator_event(struct notifier_block *nb, return 0; } +static int aic31xx_reset(struct aic31xx_priv *aic31xx) +{ + int ret = 0; + + if (aic31xx->gpio_reset) { + gpiod_set_value(aic31xx->gpio_reset, 1); + ndelay(10); /* At least 10ns */ + gpiod_set_value(aic31xx->gpio_reset, 0); + } else { + ret = regmap_write(aic31xx->regmap, AIC31XX_RESET, 1); + } + mdelay(1); /* At least 1ms */ + + return ret; +} + static void aic31xx_clk_on(struct snd_soc_codec *codec) { struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); @@ -1098,11 +1114,13 @@ static int aic31xx_power_on(struct snd_soc_codec *codec) if (ret) return ret; - if (aic31xx->gpio_reset) { - gpiod_set_value(aic31xx->gpio_reset, 0); - udelay(100); - } regcache_cache_only(aic31xx->regmap, false); + + /* Reset device registers for a consistent power-on like state */ + ret = aic31xx_reset(aic31xx); + if (ret < 0) + dev_err(aic31xx->dev, "Could not reset device: %d\n", ret); + ret = regcache_sync(aic31xx->regmap); if (ret) { dev_err(codec->dev, -- cgit v1.2.3 From 2e2d53da81af6b2222c6b4e025a5d01b37b4449b Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Thu, 7 Dec 2017 22:15:39 -0800 Subject: ASoC: rsnd: ssi: remove unnesessary period_pos period_pos can always be calculated by byte_pos and byte_per_period, there is no reason to maintain this variable in rsnd_dai_stream. This patch removes period_pos from rsnd_ssi and calculates next_period_byte with consideration of actual byte_pos value. Signed-off-by: Jiada Wang Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index cbf3bf312d23..f21202429000 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -80,7 +80,6 @@ struct rsnd_ssi { unsigned int usrcnt; int byte_pos; - int period_pos; int byte_per_period; int next_period_byte; }; @@ -421,7 +420,6 @@ static void rsnd_ssi_pointer_init(struct rsnd_mod *mod, struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); ssi->byte_pos = 0; - ssi->period_pos = 0; ssi->byte_per_period = runtime->period_size * runtime->channels * samples_to_bytes(runtime, 1); @@ -453,13 +451,12 @@ static bool rsnd_ssi_pointer_update(struct rsnd_mod *mod, if (byte_pos >= ssi->next_period_byte) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + int period_pos = byte_pos / ssi->byte_per_period; - ssi->period_pos++; - ssi->next_period_byte += ssi->byte_per_period; + ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period; - if (ssi->period_pos >= runtime->periods) { + if (period_pos >= runtime->periods) { byte_pos = 0; - ssi->period_pos = 0; ssi->next_period_byte = ssi->byte_per_period; } -- cgit v1.2.3 From a914e44693d41ba43604afa8c435c98a6d2c7cb1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 8 Dec 2017 06:23:11 +0000 Subject: ASoC: rsnd: more clear rsnd_get_dalign() for DALIGN On Renesas sound device, DALIGN which exchanges channel position is needed because SW and HW are using defferent data order if 16bit data. It is not needed when 24bit data. rsnd_get_dalign() returns necessary value, but it was confusable code. This patch makes it more simple. Tested-by: Hiroyuki Yokoyama Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index d76ad46a6fd9..8e50b284230d 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -294,11 +294,12 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); struct rsnd_mod *target; struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - u32 val = 0x76543210; - u32 mask = ~0; /* - * *Hardware* L/R and *Software* L/R are inverted. + * *Hardware* L/R and *Software* L/R are inverted for 16bit data. + * 31..16 15...0 + * HW: [L ch] [R ch] + * SW: [R ch] [L ch] * We need to care about inversion timing to control * Playback/Capture correctly. * The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R @@ -325,27 +326,13 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) target = cmd ? cmd : ssiu; } - mask <<= runtime->channels * 4; - val = val & mask; - - switch (runtime->sample_bits) { - case 16: - val |= 0x67452301 & ~mask; - break; - case 32: - val |= 0x76543210 & ~mask; - break; - } - - /* - * exchange channeles on SRC if possible, - * otherwise, R/L volume settings on DVC - * changes inverted channels - */ - if (mod == target) - return val; - else + /* Non target mod or 24bit data needs normal DALIGN */ + if ((runtime->sample_bits != 16) || + (mod != target)) return 0x76543210; + /* Target mod needs inverted DALIGN when 16bit */ + else + return 0x67452301; } u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) -- cgit v1.2.3 From cd430a244cd5d3ca0f4053718eabdf42bc12c517 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 9 Dec 2017 14:52:03 +0300 Subject: ASoC: nuc900: Fix platform_get_irq() error checking some more The error handling doesn't work here because "nuc900_audio->irq_num" is unsigned. Also we should be checking for < 0 and not <= 0 but I believe that's harmless. The platform_get_irq() comments don't talk about the return values... Fixes: fa8cc38165c2 ("ASoC: nuc900: Fix platform_get_irq's error checking") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/nuc900/nuc900-ac97.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index 5e4fbd2d3479..71fce7c85c93 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c @@ -345,11 +345,10 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev) goto out; } - nuc900_audio->irq_num = platform_get_irq(pdev, 0); - if (nuc900_audio->irq_num <= 0) { - ret = nuc900_audio->irq_num < 0 ? nuc900_audio->irq_num : -EBUSY; + ret = platform_get_irq(pdev, 0); + if (ret < 0) goto out; - } + nuc900_audio->irq_num = ret; nuc900_ac97_data = nuc900_audio; -- cgit v1.2.3 From 65a12b3aafed5fc59f4ce41b22b752b1729e6701 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 9 Dec 2017 14:52:28 +0300 Subject: ASoC: nuc900: Fix a loop timeout test We should be finishing the loop with timeout set to zero but because this is a post-op we finish with timeout == -1. Fixes: 1082e2703a2d ("ASoC: NUC900/audio: add nuc900 audio driver support") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/nuc900/nuc900-ac97.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index 71fce7c85c93..81b09d740ed9 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c @@ -67,7 +67,7 @@ static unsigned short nuc900_ac97_read(struct snd_ac97 *ac97, /* polling the AC_R_FINISH */ while (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_R_FINISH) - && timeout--) + && --timeout) mdelay(1); if (!timeout) { @@ -121,7 +121,7 @@ static void nuc900_ac97_write(struct snd_ac97 *ac97, unsigned short reg, /* polling the AC_W_FINISH */ while ((AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_W_FINISH) - && timeout--) + && --timeout) mdelay(1); if (!timeout) -- cgit v1.2.3 From 87684d338a22d15e47b16ee68f569d74ad1d076e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 8 Dec 2017 14:54:25 +0300 Subject: ASoC: Intel: Skylake: Re-order some code to silence a warning I get a Smatch warning here: sound/soc/intel/skylake/skl-nhlt.c:335 skl_get_ssp_clks() error: testing array offset 'j' after use. The code is harmless, but the checker is right that we should swap these two conditions so we verify that the offset is within bounds before we use it. Signed-off-by: Dan Carpenter Reviewed-by: Sriram Periyasamy Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-nhlt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index ca5dc2be7b68..bde7f40f29f5 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -322,8 +322,8 @@ static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, rate = channels * bps * fs; /* check if the rate is added already to the given SSP's sclk */ - for (j = 0; (sclk[id].rate_cfg[j].rate != 0) && - (j < SKL_MAX_CLK_RATES); j++) { + for (j = 0; (j < SKL_MAX_CLK_RATES) && + (sclk[id].rate_cfg[j].rate != 0); j++) { if (sclk[id].rate_cfg[j].rate == rate) { present = true; break; -- cgit v1.2.3 From 41acc8ec04f32abb16e035ca1c9fe4d52819601e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 11 Dec 2017 02:24:23 +0000 Subject: ASoC: rsnd: don't use runtime->sample_bits Current rsnd driver is judging 16bit/24bit data by using runtime->sample_bits, but it is indicating physical size, not format size. This is confusable code. This patch uses snd_pcm_format_width() to be more correct code. Tested-by: Hiroyuki Yokoyama Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 12 ++++-------- sound/soc/sh/rcar/ssi.c | 9 +++------ 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 8e50b284230d..a96ebebd96de 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -274,10 +274,10 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct device *dev = rsnd_priv_to_dev(priv); - switch (runtime->sample_bits) { + switch (snd_pcm_format_width(runtime->format)) { case 16: return 8 << 16; - case 32: + case 24: return 0 << 16; } @@ -327,7 +327,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) } /* Non target mod or 24bit data needs normal DALIGN */ - if ((runtime->sample_bits != 16) || + if ((snd_pcm_format_width(runtime->format) != 16) || (mod != target)) return 0x76543210; /* Target mod needs inverted DALIGN when 16bit */ @@ -362,12 +362,8 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) * HW 24bit data is located as 0x******00 * */ - switch (runtime->sample_bits) { - case 16: + if (snd_pcm_format_width(runtime->format) == 16) return 0; - case 32: - break; - } for (i = 0; i < ARRAY_SIZE(playback_mods); i++) { tmod = rsnd_io_to_mod(io, mods[i]); diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index f21202429000..5a70fdc3c680 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -370,11 +370,11 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, if (rsnd_io_is_play(io)) cr_own |= TRMD; - switch (runtime->sample_bits) { + switch (snd_pcm_format_width(runtime->format)) { case 16: cr_own |= DWL_16; break; - case 32: + case 24: cr_own |= DWL_24; break; } @@ -677,11 +677,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, rsnd_ssi_pointer_offset(mod, io, 0)); int shift = 0; - switch (runtime->sample_bits) { - case 32: + if (snd_pcm_format_width(runtime->format) == 24) shift = 8; - break; - } /* * 8/16/32 data can be assesse to TDR/RDR register -- cgit v1.2.3 From d8d9b9730cd62c9c7d24d5277542da98c09ea728 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 11 Dec 2017 02:40:22 +0000 Subject: ASoC: rsnd: PIO related function cleanup SSI had shared counting pointer position method between PIO/DMA mode before. But now DMA mode is using DMAEngine feature to get it. Thus, this counting pointer position method is needed for only PIO mode. We don't need to share code anymore. This patch names PIO related functions as rsnd_ssi_pio_xxx(), and merged/cleanuped each feature. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 153 +++++++++++++++++++++++------------------------- 1 file changed, 72 insertions(+), 81 deletions(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 5a70fdc3c680..97a9db892a8f 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -79,6 +79,7 @@ struct rsnd_ssi { int irq; unsigned int usrcnt; + /* for PIO */ int byte_pos; int byte_per_period; int next_period_byte; @@ -413,61 +414,6 @@ static void rsnd_ssi_register_setup(struct rsnd_mod *mod) ssi->cr_en); } -static void rsnd_ssi_pointer_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - - ssi->byte_pos = 0; - ssi->byte_per_period = runtime->period_size * - runtime->channels * - samples_to_bytes(runtime, 1); - ssi->next_period_byte = ssi->byte_per_period; -} - -static int rsnd_ssi_pointer_offset(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - int additional) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - int pos = ssi->byte_pos + additional; - - pos %= (runtime->periods * ssi->byte_per_period); - - return pos; -} - -static bool rsnd_ssi_pointer_update(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - int byte) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - bool ret = false; - int byte_pos; - - byte_pos = ssi->byte_pos + byte; - - if (byte_pos >= ssi->next_period_byte) { - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - int period_pos = byte_pos / ssi->byte_per_period; - - ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period; - - if (period_pos >= runtime->periods) { - byte_pos = 0; - ssi->next_period_byte = ssi->byte_per_period; - } - - ret = true; - } - - WRITE_ONCE(ssi->byte_pos, byte_pos); - - return ret; -} - /* * SSI mod common functions */ @@ -481,8 +427,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, if (!rsnd_ssi_is_run_mods(mod, io)) return 0; - rsnd_ssi_pointer_init(mod, io); - ssi->usrcnt++; rsnd_mod_power_on(mod); @@ -653,6 +597,8 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod, return 0; } +static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod, + struct rsnd_dai_stream *io); static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { @@ -671,27 +617,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, status = rsnd_ssi_status_get(mod); /* PIO only */ - if (!is_dma && (status & DIRQ)) { - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - u32 *buf = (u32 *)(runtime->dma_area + - rsnd_ssi_pointer_offset(mod, io, 0)); - int shift = 0; - - if (snd_pcm_format_width(runtime->format) == 24) - shift = 8; - - /* - * 8/16/32 data can be assesse to TDR/RDR register - * directly as 32bit data - * see rsnd_ssi_init() - */ - if (rsnd_io_is_play(io)) - rsnd_mod_write(mod, SSITDR, (*buf) << shift); - else - *buf = (rsnd_mod_read(mod, SSIRDR) >> shift); - - elapsed = rsnd_ssi_pointer_update(mod, io, sizeof(*buf)); - } + if (!is_dma && (status & DIRQ)) + elapsed = rsnd_ssi_pio_interrupt(mod, io); /* DMA only */ if (is_dma && (status & (UIRQ | OIRQ))) @@ -829,7 +756,71 @@ static int rsnd_ssi_common_remove(struct rsnd_mod *mod, return 0; } -static int rsnd_ssi_pointer(struct rsnd_mod *mod, +/* + * SSI PIO functions + */ +static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod, + struct rsnd_dai_stream *io) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + u32 *buf = (u32 *)(runtime->dma_area + ssi->byte_pos); + int shift = 0; + int byte_pos; + bool elapsed = false; + + if (snd_pcm_format_width(runtime->format) == 24) + shift = 8; + + /* + * 8/16/32 data can be assesse to TDR/RDR register + * directly as 32bit data + * see rsnd_ssi_init() + */ + if (rsnd_io_is_play(io)) + rsnd_mod_write(mod, SSITDR, (*buf) << shift); + else + *buf = (rsnd_mod_read(mod, SSIRDR) >> shift); + + byte_pos = ssi->byte_pos + sizeof(*buf); + + if (byte_pos >= ssi->next_period_byte) { + int period_pos = byte_pos / ssi->byte_per_period; + + if (period_pos >= runtime->periods) { + byte_pos = 0; + period_pos = 0; + } + + ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period; + + elapsed = true; + } + + WRITE_ONCE(ssi->byte_pos, byte_pos); + + return elapsed; +} + +static int rsnd_ssi_pio_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + + if (!rsnd_ssi_is_parent(mod, io)) { + ssi->byte_pos = 0; + ssi->byte_per_period = runtime->period_size * + runtime->channels * + samples_to_bytes(runtime, 1); + ssi->next_period_byte = ssi->byte_per_period; + } + + return rsnd_ssi_init(mod, io, priv); +} + +static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod, struct rsnd_dai_stream *io, snd_pcm_uframes_t *pointer) { @@ -845,12 +836,12 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = { .name = SSI_NAME, .probe = rsnd_ssi_common_probe, .remove = rsnd_ssi_common_remove, - .init = rsnd_ssi_init, + .init = rsnd_ssi_pio_init, .quit = rsnd_ssi_quit, .start = rsnd_ssi_start, .stop = rsnd_ssi_stop, .irq = rsnd_ssi_irq, - .pointer= rsnd_ssi_pointer, + .pointer = rsnd_ssi_pio_pointer, .pcm_new = rsnd_ssi_pcm_new, .hw_params = rsnd_ssi_hw_params, }; -- cgit v1.2.3 From 9f761183947b91aacc4ed5c2a1a39ac08b938b6c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 11 Dec 2017 02:43:41 +0000 Subject: ASoC: rsnd: remove unneeded "is_graph" from __rsnd_dai_probe() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index a96ebebd96de..64d5ecb86528 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1017,7 +1017,7 @@ of_node_compatible: static void __rsnd_dai_probe(struct rsnd_priv *priv, struct device_node *dai_np, - int dai_i, int is_graph) + int dai_i) { struct device_node *playback, *capture; struct rsnd_dai_stream *io_playback; @@ -1116,13 +1116,13 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) dai_i = 0; if (is_graph) { for_each_endpoint_of_node(dai_node, dai_np) { - __rsnd_dai_probe(priv, dai_np, dai_i, is_graph); + __rsnd_dai_probe(priv, dai_np, dai_i); rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i); dai_i++; } } else { for_each_child_of_node(dai_node, dai_np) - __rsnd_dai_probe(priv, dai_np, dai_i++, is_graph); + __rsnd_dai_probe(priv, dai_np, dai_i++); } return 0; -- cgit v1.2.3 From 21faaea1343f2f8dc6539302c92231afc6d999a5 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 12 Dec 2017 16:11:45 +0800 Subject: ASoC: sun4i-i2s: Add support for A83T The I2S controller in the A83T is mostly compatible with the one found in earlier SoCs such as the A20 and A31. While the documents publicly available for the A83T do not cover this hardware, the officially released BSP kernel does have register definitions for it. These were matched against the A20 user manual. The only difference is the TX FIFO and interrupt status registers have been swapped around, like what we have seen with the SPDIF controller. This patch adds support for this hardware. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sun4i-i2s.txt | 2 ++ sound/soc/sunxi/sun4i-i2s.c | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt index 05d7135a8d2f..b9d50d6cdef3 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt @@ -8,6 +8,7 @@ Required properties: - compatible: should be one of the following: - "allwinner,sun4i-a10-i2s" - "allwinner,sun6i-a31-i2s" + - "allwinner,sun8i-a83t-i2s" - "allwinner,sun8i-h3-i2s" - reg: physical base address of the controller and length of memory mapped region. @@ -23,6 +24,7 @@ Required properties: Required properties for the following compatibles: - "allwinner,sun6i-a31-i2s" + - "allwinner,sun8i-a83t-i2s" - "allwinner,sun8i-h3-i2s" - resets: phandle to the reset line for this codec diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 04f92583a969..13d7ecabe1b6 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -897,6 +897,23 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), }; +static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { + .has_reset = true, + .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, + .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, + .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), + .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), + .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), + .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), + .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), + .has_slave_select_bit = true, + .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), + .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), + .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), + .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), + .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), +}; + static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, @@ -1120,6 +1137,10 @@ static const struct of_device_id sun4i_i2s_match[] = { .compatible = "allwinner,sun6i-a31-i2s", .data = &sun6i_a31_i2s_quirks, }, + { + .compatible = "allwinner,sun8i-a83t-i2s", + .data = &sun8i_a83t_i2s_quirks, + }, { .compatible = "allwinner,sun8i-h3-i2s", .data = &sun8i_h3_i2s_quirks, -- cgit v1.2.3 From 5a0cf02465a0510c48ab34e7ba88b0f8c20b9ea1 Mon Sep 17 00:00:00 2001 From: Andrea Bondavalli Date: Tue, 12 Dec 2017 10:14:50 +0100 Subject: ASoC: sun4i-codec: enable 12Khz and 24Khz audio sample rates H3 ASoC supports 12Khz and 24Khz audio sample rates but the current drivers doesn't advertise these rates properly and they cannot be used. For example attempt to capture at 12Khz uses 11Khz (same applies to audio playback): Recording raw data '/tmp/testS16_LE.raw' : Signed 16 bit Little Endian, Rate 12000 Hz, Stereo Warning: rate is not accurate (requested = 12000Hz, got = 11025Hz) This patch fixes the audio sample rates declared and supported by the driver according to the H3 data sheet. Specifically for audio playback: 8000, 11050, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 96000, 192000 and for audio capture: 8000, 11050, 12000, 16000, 22050, 24000, 32000, 44100, 48000 Signed-off-by: Andrea Bondavalli Acked-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 5da4efe7a550..886281673972 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -590,12 +590,28 @@ static int sun4i_codec_hw_params(struct snd_pcm_substream *substream, hwrate); } + +static unsigned int sun4i_codec_src_rates[] = { + 8000, 11025, 12000, 16000, 22050, 24000, 32000, + 44100, 48000, 96000, 192000 +}; + + +static struct snd_pcm_hw_constraint_list sun4i_codec_constraints = { + .count = ARRAY_SIZE(sun4i_codec_src_rates), + .list = sun4i_codec_src_rates, +}; + + static int sun4i_codec_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &sun4i_codec_constraints); + /* * Stop issuing DRQ when we have room for less than 16 samples * in our TX FIFO @@ -633,9 +649,7 @@ static struct snd_soc_dai_driver sun4i_codec_dai = { .channels_max = 2, .rate_min = 8000, .rate_max = 192000, - .rates = SNDRV_PCM_RATE_8000_48000 | - SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000, + .rates = SNDRV_PCM_RATE_CONTINUOUS, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .sig_bits = 24, @@ -645,11 +659,8 @@ static struct snd_soc_dai_driver sun4i_codec_dai = { .channels_min = 1, .channels_max = 2, .rate_min = 8000, - .rate_max = 192000, - .rates = SNDRV_PCM_RATE_8000_48000 | - SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000 | - SNDRV_PCM_RATE_KNOT, + .rate_max = 48000, + .rates = SNDRV_PCM_RATE_CONTINUOUS, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .sig_bits = 24, @@ -1128,7 +1139,7 @@ static const struct snd_soc_component_driver sun4i_codec_component = { .name = "sun4i-codec", }; -#define SUN4I_CODEC_RATES SNDRV_PCM_RATE_8000_192000 +#define SUN4I_CODEC_RATES SNDRV_PCM_RATE_CONTINUOUS #define SUN4I_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S32_LE) -- cgit v1.2.3 From d61f9982c2a395407a75a4f7057c4a3f55bda462 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 11 Dec 2017 15:26:14 +0100 Subject: ASoC: tfa9879: clean up bindings Fix a couple of nitpicks: - list #sound-dai-cells as a required property. - The chip supports full speed I2C; don't indicate standard mode only. - status = "okay" is just noise. - The chip is an amplifier, not a codec. - consistently indent with tabs. Signed-off-by: Peter Rosin Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/tfa9879.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/tfa9879.txt b/Documentation/devicetree/bindings/sound/tfa9879.txt index 23ba522d9e2b..1620e6848436 100644 --- a/Documentation/devicetree/bindings/sound/tfa9879.txt +++ b/Documentation/devicetree/bindings/sound/tfa9879.txt @@ -6,18 +6,18 @@ Required properties: - reg : the I2C address of the device +- #sound-dai-cells : must be 0. + Example: &i2c1 { - clock-frequency = <100000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c1>; - status = "okay"; - codec: tfa9879@6c { + amp: amp@6c { #sound-dai-cells = <0>; compatible = "nxp,tfa9879"; reg = <0x6c>; - }; + }; }; -- cgit v1.2.3 From a73be94364b80388c0a600715117923669f165f8 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 11 Dec 2017 15:26:15 +0100 Subject: ASoC: tfa9879: add DT bindings to MAINTAINERS Let's keep maintenance of the driver and the bindings in one place. Signed-off-by: Peter Rosin Signed-off-by: Mark Brown --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index aa71ab52fd76..a04aaa270ad5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9805,6 +9805,7 @@ NXP TFA9879 DRIVER M: Peter Rosin L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained +F: Documentation/devicetree/bindings/sound/tfa9879.txt F: sound/soc/codecs/tfa9879* NXP-NCI NFC DRIVER -- cgit v1.2.3 From aa9c387c2dc25597b730cd8386cac8ccfe75de07 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 11 Dec 2017 22:26:40 +0100 Subject: ASoC: rt5645: Set card long_name for GPD win / pocket The GPD win and pocket devices both use the same codec setup and both have too generic dmi strings making snd_soc_set_dmi_name() not work. As these devices have only a single speaker we want a separate ucm file for them, which requires a unique long_name, use the existing GPD quirk handling to also provide a unique long_name. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- include/sound/rt5645.h | 3 +++ sound/soc/codecs/rt5645.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/include/sound/rt5645.h b/include/sound/rt5645.h index d0c33a9972b9..f218c742f08e 100644 --- a/include/sound/rt5645.h +++ b/include/sound/rt5645.h @@ -25,6 +25,9 @@ struct rt5645_platform_data { bool level_trigger_irq; /* Invert JD1_1 status polarity */ bool inv_jd1_1; + + /* Value to asign to snd_soc_card.long_name */ + const char *long_name; }; #endif diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index fcd02c2c76f1..a1a7bb770745 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3394,6 +3394,9 @@ static int rt5645_probe(struct snd_soc_codec *codec) snd_soc_dapm_sync(dapm); } + if (rt5645->pdata.long_name) + codec->component.card->long_name = rt5645->pdata.long_name; + rt5645->eq_param = devm_kzalloc(codec->dev, RT5645_HWEQ_NUM * sizeof(struct rt5645_eq_param_s), GFP_KERNEL); @@ -3624,6 +3627,7 @@ static const struct dmi_system_id dmi_platform_intel_broadwell[] = { static const struct rt5645_platform_data gpd_win_platform_data = { .jd_mode = 3, .inv_jd1_1 = true, + .long_name = "gpd-win-pocket-rt5645", }; static const struct dmi_system_id dmi_platform_gpd_win[] = { -- cgit v1.2.3 From 872bcad246e30f0ae8009a0f8c13874009601445 Mon Sep 17 00:00:00 2001 From: Andreas Dannenberg Date: Mon, 11 Dec 2017 13:01:54 -0600 Subject: ASoC: tas5720: add basic support for TAS5722 devices The TI TAS5722 digital amplifier is very similar to the TAS5720 from an overall and register map perspective. Therefore the existing driver can be extended easily to support this additional device. This commit allows TAS5722 devices to be used in a "subset" type of fashion, without exposing any of the additional features they offer. Signed-off-by: Andreas Dannenberg Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/tas5720.txt | 4 ++- sound/soc/codecs/tas5720.c | 38 ++++++++++++++++++---- sound/soc/codecs/tas5720.h | 1 + 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/tas5720.txt b/Documentation/devicetree/bindings/sound/tas5720.txt index 40d94f82beb3..7481653fe8e3 100644 --- a/Documentation/devicetree/bindings/sound/tas5720.txt +++ b/Documentation/devicetree/bindings/sound/tas5720.txt @@ -6,10 +6,12 @@ audio playback. For more product information please see the links below: http://www.ti.com/product/TAS5720L http://www.ti.com/product/TAS5720M +http://www.ti.com/product/TAS5722L Required properties: -- compatible : "ti,tas5720" +- compatible : "ti,tas5720", + "ti,tas5722" - reg : I2C slave address - dvdd-supply : phandle to a 3.3-V supply for the digital circuitry - pvdd-supply : phandle to a supply used for the Class-D amp and the analog diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index a736a2a6976c..5def54d1336d 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -36,6 +36,11 @@ /* Define how often to check (and clear) the fault status register (in ms) */ #define TAS5720_FAULT_CHECK_INTERVAL 200 +enum tas572x_type { + TAS5720, + TAS5722, +}; + static const char * const tas5720_supply_names[] = { "dvdd", /* Digital power supply. Connect to 3.3-V supply. */ "pvdd", /* Class-D amp and analog power supply (connected). */ @@ -47,6 +52,7 @@ struct tas5720_data { struct snd_soc_codec *codec; struct regmap *regmap; struct i2c_client *tas5720_client; + enum tas572x_type devtype; struct regulator_bulk_data supplies[TAS5720_NUM_SUPPLIES]; struct delayed_work fault_check_work; unsigned int last_fault; @@ -264,7 +270,7 @@ out: static int tas5720_codec_probe(struct snd_soc_codec *codec) { struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec); - unsigned int device_id; + unsigned int device_id, expected_device_id; int ret; tas5720->codec = codec; @@ -276,6 +282,11 @@ static int tas5720_codec_probe(struct snd_soc_codec *codec) return ret; } + /* + * Take a liberal approach to checking the device ID to allow the + * driver to be used even if the device ID does not match, however + * issue a warning if there is a mismatch. + */ ret = regmap_read(tas5720->regmap, TAS5720_DEVICE_ID_REG, &device_id); if (ret < 0) { dev_err(codec->dev, "failed to read device ID register: %d\n", @@ -283,13 +294,22 @@ static int tas5720_codec_probe(struct snd_soc_codec *codec) goto probe_fail; } - if (device_id != TAS5720_DEVICE_ID) { - dev_err(codec->dev, "wrong device ID. expected: %u read: %u\n", - TAS5720_DEVICE_ID, device_id); - ret = -ENODEV; - goto probe_fail; + switch (tas5720->devtype) { + case TAS5720: + expected_device_id = TAS5720_DEVICE_ID; + break; + case TAS5722: + expected_device_id = TAS5722_DEVICE_ID; + break; + default: + dev_err(codec->dev, "unexpected private driver data\n"); + return -EINVAL; } + if (device_id != expected_device_id) + dev_warn(codec->dev, "wrong device ID. expected: %u read: %u\n", + expected_device_id, device_id); + /* Set device to mute */ ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL2_REG, TAS5720_MUTE, TAS5720_MUTE); @@ -552,6 +572,8 @@ static int tas5720_probe(struct i2c_client *client, return -ENOMEM; data->tas5720_client = client; + data->devtype = id->driver_data; + data->regmap = devm_regmap_init_i2c(client, &tas5720_regmap_config); if (IS_ERR(data->regmap)) { ret = PTR_ERR(data->regmap); @@ -592,7 +614,8 @@ static int tas5720_remove(struct i2c_client *client) } static const struct i2c_device_id tas5720_id[] = { - { "tas5720", 0 }, + { "tas5720", TAS5720 }, + { "tas5722", TAS5722 }, { } }; MODULE_DEVICE_TABLE(i2c, tas5720_id); @@ -600,6 +623,7 @@ MODULE_DEVICE_TABLE(i2c, tas5720_id); #if IS_ENABLED(CONFIG_OF) static const struct of_device_id tas5720_of_match[] = { { .compatible = "ti,tas5720", }, + { .compatible = "ti,tas5722", }, { }, }; MODULE_DEVICE_TABLE(of, tas5720_of_match); diff --git a/sound/soc/codecs/tas5720.h b/sound/soc/codecs/tas5720.h index 3d077c779b12..bef802afcc69 100644 --- a/sound/soc/codecs/tas5720.h +++ b/sound/soc/codecs/tas5720.h @@ -32,6 +32,7 @@ /* TAS5720_DEVICE_ID_REG */ #define TAS5720_DEVICE_ID 0x01 +#define TAS5722_DEVICE_ID 0x12 /* TAS5720_POWER_CTRL_REG */ #define TAS5720_DIG_CLIP_MASK GENMASK(7, 2) -- cgit v1.2.3 From d5eb436acc8104b5c789359aa8c923ff5fafcd62 Mon Sep 17 00:00:00 2001 From: Andreas Dannenberg Date: Mon, 11 Dec 2017 13:01:55 -0600 Subject: ASoC: tas5720: add TAS5722 register support Introduce a custom super-set register map and associated bit definitions to allow driver access to all TAS5722 device functionality. Signed-off-by: Andreas Dannenberg Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tas5720.c | 23 ++++++++++++++++++++++- sound/soc/codecs/tas5720.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index 5def54d1336d..f3006f301fe8 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -466,6 +466,15 @@ static const struct regmap_config tas5720_regmap_config = { .volatile_reg = tas5720_is_volatile_reg, }; +static const struct regmap_config tas5722_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = TAS5722_MAX_REG, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = tas5720_is_volatile_reg, +}; + /* * DAC analog gain. There are four discrete values to select from, ranging * from 19.2 dB to 26.3dB. @@ -564,6 +573,7 @@ static int tas5720_probe(struct i2c_client *client, { struct device *dev = &client->dev; struct tas5720_data *data; + const struct regmap_config *regmap_config; int ret; int i; @@ -574,7 +584,18 @@ static int tas5720_probe(struct i2c_client *client, data->tas5720_client = client; data->devtype = id->driver_data; - data->regmap = devm_regmap_init_i2c(client, &tas5720_regmap_config); + switch (id->driver_data) { + case TAS5720: + regmap_config = &tas5720_regmap_config; + break; + case TAS5722: + regmap_config = &tas5722_regmap_config; + break; + default: + dev_err(dev, "unexpected private driver data\n"); + return -EINVAL; + } + data->regmap = devm_regmap_init_i2c(client, regmap_config); if (IS_ERR(data->regmap)) { ret = PTR_ERR(data->regmap); dev_err(dev, "failed to allocate register map: %d\n", ret); diff --git a/sound/soc/codecs/tas5720.h b/sound/soc/codecs/tas5720.h index bef802afcc69..1dda3095961d 100644 --- a/sound/soc/codecs/tas5720.h +++ b/sound/soc/codecs/tas5720.h @@ -30,6 +30,11 @@ #define TAS5720_DIGITAL_CLIP1_REG 0x11 #define TAS5720_MAX_REG TAS5720_DIGITAL_CLIP1_REG +/* Additional TAS5722-specific Registers */ +#define TAS5722_DIGITAL_CTRL2_REG 0x13 +#define TAS5722_ANALOG_CTRL2_REG 0x14 +#define TAS5722_MAX_REG TAS5722_ANALOG_CTRL2_REG + /* TAS5720_DEVICE_ID_REG */ #define TAS5720_DEVICE_ID 0x01 #define TAS5722_DEVICE_ID 0x12 @@ -52,6 +57,7 @@ #define TAS5720_SAIF_FORMAT_MASK GENMASK(2, 0) /* TAS5720_DIGITAL_CTRL2_REG */ +#define TAS5722_VOL_RAMP_RATE BIT(6) #define TAS5720_MUTE BIT(4) #define TAS5720_TDM_SLOT_SEL_MASK GENMASK(2, 0) @@ -88,4 +94,28 @@ #define TAS5720_CLIP1_MASK GENMASK(7, 2) #define TAS5720_CLIP1_SHIFT (0x2) +/* TAS5722_DIGITAL_CTRL2_REG */ +#define TAS5722_HPF_3_7HZ (0x0 << 5) +#define TAS5722_HPF_7_4HZ (0x1 << 5) +#define TAS5722_HPF_14_9HZ (0x2 << 5) +#define TAS5722_HPF_29_7HZ (0x3 << 5) +#define TAS5722_HPF_59_4HZ (0x4 << 5) +#define TAS5722_HPF_118_4HZ (0x5 << 5) +#define TAS5722_HPF_235_0HZ (0x6 << 5) +#define TAS5722_HPF_463_2HZ (0x7 << 5) +#define TAS5722_HPF_MASK GENMASK(7, 5) +#define TAS5722_AUTO_SLEEP_OFF (0x0 << 3) +#define TAS5722_AUTO_SLEEP_1024LR (0x1 << 3) +#define TAS5722_AUTO_SLEEP_65536LR (0x2 << 3) +#define TAS5722_AUTO_SLEEP_262144LR (0x3 << 3) +#define TAS5722_AUTO_SLEEP_MASK GENMASK(4, 3) +#define TAS5722_TDM_SLOT_16B BIT(2) +#define TAS5722_MCLK_PIN_CFG BIT(1) +#define TAS5722_VOL_CONTROL_LSB BIT(0) + +/* TAS5722_ANALOG_CTRL2_REG */ +#define TAS5722_FAULTZ_PU BIT(3) +#define TAS5722_VREG_LVL BIT(2) +#define TAS5722_PWR_TUNE BIT(0) + #endif /* __TAS5720_H__ */ -- cgit v1.2.3 From b0a858a47a7889757dbc9ac9872685955eaa5cc0 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 12 Dec 2017 18:09:15 +0000 Subject: ASoC: rsnd: Add device tree support for r8a774[35] Document r8a774[35] specific compatible strings. The Renesas RZ/G1[ME] (r8a774[35]) sound modules are identical to the R-Car Gen2 family. No driver change is needed as the fallback compatible string "renesas,rcar_sound-gen2" activates the right code in the driver. Signed-off-by: Biju Das Reviewed-by: Fabrizio Castro Reviewed-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 085bec364caf..b3c28bdcc268 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -4,7 +4,7 @@ Renesas R-Car sound * Modules ============================================= -Renesas R-Car sound is constructed from below modules +Renesas R-Car and RZ/G sound is constructed from below modules (for Gen2 or later) SCU : Sampling Rate Converter Unit @@ -334,9 +334,11 @@ Required properties: - compatible : "renesas,rcar_sound-", fallbacks "renesas,rcar_sound-gen1" if generation1, and - "renesas,rcar_sound-gen2" if generation2 + "renesas,rcar_sound-gen2" if generation2 (or RZ/G1) "renesas,rcar_sound-gen3" if generation3 Examples with soctypes are: + - "renesas,rcar_sound-r8a7743" (RZ/G1M) + - "renesas,rcar_sound-r8a7745" (RZ/G1E) - "renesas,rcar_sound-r8a7778" (R-Car M1A) - "renesas,rcar_sound-r8a7779" (R-Car H1) - "renesas,rcar_sound-r8a7790" (R-Car H2) -- cgit v1.2.3 From 1714196c7ec540292324d9022c43b5f281dbf74c Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 12 Dec 2017 16:43:03 -0600 Subject: ASoC: tlv320aic32x4: Use AIC32X4_REG macro for all register definitions All register definitions should use the AIC32X4_REG macro, even the ones in page 0. This makes datasheet lookup more consistent and helps with alignment both in this file and across other tlv320aic* drivers. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.h | 152 ++++++++++++++++++++------------------- 1 file changed, 77 insertions(+), 75 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index da7cec482bcb..936bb7a1b5c8 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -19,81 +19,83 @@ int aic32x4_remove(struct device *dev); /* tlv320aic32x4 register space (in decimal to match datasheet) */ -#define AIC32X4_PAGE1 128 - -#define AIC32X4_PSEL 0 -#define AIC32X4_RESET 1 -#define AIC32X4_CLKMUX 4 -#define AIC32X4_PLLPR 5 -#define AIC32X4_PLLJ 6 -#define AIC32X4_PLLDMSB 7 -#define AIC32X4_PLLDLSB 8 -#define AIC32X4_NDAC 11 -#define AIC32X4_MDAC 12 -#define AIC32X4_DOSRMSB 13 -#define AIC32X4_DOSRLSB 14 -#define AIC32X4_NADC 18 -#define AIC32X4_MADC 19 -#define AIC32X4_AOSR 20 -#define AIC32X4_CLKMUX2 25 -#define AIC32X4_CLKOUTM 26 -#define AIC32X4_IFACE1 27 -#define AIC32X4_IFACE2 28 -#define AIC32X4_IFACE3 29 -#define AIC32X4_BCLKN 30 -#define AIC32X4_IFACE4 31 -#define AIC32X4_IFACE5 32 -#define AIC32X4_IFACE6 33 -#define AIC32X4_GPIOCTL 52 -#define AIC32X4_DOUTCTL 53 -#define AIC32X4_DINCTL 54 -#define AIC32X4_MISOCTL 55 -#define AIC32X4_SCLKCTL 56 -#define AIC32X4_DACSPB 60 -#define AIC32X4_ADCSPB 61 -#define AIC32X4_DACSETUP 63 -#define AIC32X4_DACMUTE 64 -#define AIC32X4_LDACVOL 65 -#define AIC32X4_RDACVOL 66 -#define AIC32X4_ADCSETUP 81 -#define AIC32X4_ADCFGA 82 -#define AIC32X4_LADCVOL 83 -#define AIC32X4_RADCVOL 84 -#define AIC32X4_LAGC1 86 -#define AIC32X4_LAGC2 87 -#define AIC32X4_LAGC3 88 -#define AIC32X4_LAGC4 89 -#define AIC32X4_LAGC5 90 -#define AIC32X4_LAGC6 91 -#define AIC32X4_LAGC7 92 -#define AIC32X4_RAGC1 94 -#define AIC32X4_RAGC2 95 -#define AIC32X4_RAGC3 96 -#define AIC32X4_RAGC4 97 -#define AIC32X4_RAGC5 98 -#define AIC32X4_RAGC6 99 -#define AIC32X4_RAGC7 100 -#define AIC32X4_PWRCFG (AIC32X4_PAGE1 + 1) -#define AIC32X4_LDOCTL (AIC32X4_PAGE1 + 2) -#define AIC32X4_OUTPWRCTL (AIC32X4_PAGE1 + 9) -#define AIC32X4_CMMODE (AIC32X4_PAGE1 + 10) -#define AIC32X4_HPLROUTE (AIC32X4_PAGE1 + 12) -#define AIC32X4_HPRROUTE (AIC32X4_PAGE1 + 13) -#define AIC32X4_LOLROUTE (AIC32X4_PAGE1 + 14) -#define AIC32X4_LORROUTE (AIC32X4_PAGE1 + 15) -#define AIC32X4_HPLGAIN (AIC32X4_PAGE1 + 16) -#define AIC32X4_HPRGAIN (AIC32X4_PAGE1 + 17) -#define AIC32X4_LOLGAIN (AIC32X4_PAGE1 + 18) -#define AIC32X4_LORGAIN (AIC32X4_PAGE1 + 19) -#define AIC32X4_HEADSTART (AIC32X4_PAGE1 + 20) -#define AIC32X4_MICBIAS (AIC32X4_PAGE1 + 51) -#define AIC32X4_LMICPGAPIN (AIC32X4_PAGE1 + 52) -#define AIC32X4_LMICPGANIN (AIC32X4_PAGE1 + 54) -#define AIC32X4_RMICPGAPIN (AIC32X4_PAGE1 + 55) -#define AIC32X4_RMICPGANIN (AIC32X4_PAGE1 + 57) -#define AIC32X4_FLOATINGINPUT (AIC32X4_PAGE1 + 58) -#define AIC32X4_LMICPGAVOL (AIC32X4_PAGE1 + 59) -#define AIC32X4_RMICPGAVOL (AIC32X4_PAGE1 + 60) +#define AIC32X4_REG(page, reg) ((page * 128) + reg) + +#define AIC32X4_PSEL AIC32X4_REG(0, 0) + +#define AIC32X4_RESET AIC32X4_REG(0, 1) +#define AIC32X4_CLKMUX AIC32X4_REG(0, 4) +#define AIC32X4_PLLPR AIC32X4_REG(0, 5) +#define AIC32X4_PLLJ AIC32X4_REG(0, 6) +#define AIC32X4_PLLDMSB AIC32X4_REG(0, 7) +#define AIC32X4_PLLDLSB AIC32X4_REG(0, 8) +#define AIC32X4_NDAC AIC32X4_REG(0, 11) +#define AIC32X4_MDAC AIC32X4_REG(0, 12) +#define AIC32X4_DOSRMSB AIC32X4_REG(0, 13) +#define AIC32X4_DOSRLSB AIC32X4_REG(0, 14) +#define AIC32X4_NADC AIC32X4_REG(0, 18) +#define AIC32X4_MADC AIC32X4_REG(0, 19) +#define AIC32X4_AOSR AIC32X4_REG(0, 20) +#define AIC32X4_CLKMUX2 AIC32X4_REG(0, 25) +#define AIC32X4_CLKOUTM AIC32X4_REG(0, 26) +#define AIC32X4_IFACE1 AIC32X4_REG(0, 27) +#define AIC32X4_IFACE2 AIC32X4_REG(0, 28) +#define AIC32X4_IFACE3 AIC32X4_REG(0, 29) +#define AIC32X4_BCLKN AIC32X4_REG(0, 30) +#define AIC32X4_IFACE4 AIC32X4_REG(0, 31) +#define AIC32X4_IFACE5 AIC32X4_REG(0, 32) +#define AIC32X4_IFACE6 AIC32X4_REG(0, 33) +#define AIC32X4_GPIOCTL AIC32X4_REG(0, 52) +#define AIC32X4_DOUTCTL AIC32X4_REG(0, 53) +#define AIC32X4_DINCTL AIC32X4_REG(0, 54) +#define AIC32X4_MISOCTL AIC32X4_REG(0, 55) +#define AIC32X4_SCLKCTL AIC32X4_REG(0, 56) +#define AIC32X4_DACSPB AIC32X4_REG(0, 60) +#define AIC32X4_ADCSPB AIC32X4_REG(0, 61) +#define AIC32X4_DACSETUP AIC32X4_REG(0, 63) +#define AIC32X4_DACMUTE AIC32X4_REG(0, 64) +#define AIC32X4_LDACVOL AIC32X4_REG(0, 65) +#define AIC32X4_RDACVOL AIC32X4_REG(0, 66) +#define AIC32X4_ADCSETUP AIC32X4_REG(0, 81) +#define AIC32X4_ADCFGA AIC32X4_REG(0, 82) +#define AIC32X4_LADCVOL AIC32X4_REG(0, 83) +#define AIC32X4_RADCVOL AIC32X4_REG(0, 84) +#define AIC32X4_LAGC1 AIC32X4_REG(0, 86) +#define AIC32X4_LAGC2 AIC32X4_REG(0, 87) +#define AIC32X4_LAGC3 AIC32X4_REG(0, 88) +#define AIC32X4_LAGC4 AIC32X4_REG(0, 89) +#define AIC32X4_LAGC5 AIC32X4_REG(0, 90) +#define AIC32X4_LAGC6 AIC32X4_REG(0, 91) +#define AIC32X4_LAGC7 AIC32X4_REG(0, 92) +#define AIC32X4_RAGC1 AIC32X4_REG(0, 94) +#define AIC32X4_RAGC2 AIC32X4_REG(0, 95) +#define AIC32X4_RAGC3 AIC32X4_REG(0, 96) +#define AIC32X4_RAGC4 AIC32X4_REG(0, 97) +#define AIC32X4_RAGC5 AIC32X4_REG(0, 98) +#define AIC32X4_RAGC6 AIC32X4_REG(0, 99) +#define AIC32X4_RAGC7 AIC32X4_REG(0, 100) + +#define AIC32X4_PWRCFG AIC32X4_REG(1, 1) +#define AIC32X4_LDOCTL AIC32X4_REG(1, 2) +#define AIC32X4_OUTPWRCTL AIC32X4_REG(1, 9) +#define AIC32X4_CMMODE AIC32X4_REG(1, 10) +#define AIC32X4_HPLROUTE AIC32X4_REG(1, 12) +#define AIC32X4_HPRROUTE AIC32X4_REG(1, 13) +#define AIC32X4_LOLROUTE AIC32X4_REG(1, 14) +#define AIC32X4_LORROUTE AIC32X4_REG(1, 15) +#define AIC32X4_HPLGAIN AIC32X4_REG(1, 16) +#define AIC32X4_HPRGAIN AIC32X4_REG(1, 17) +#define AIC32X4_LOLGAIN AIC32X4_REG(1, 18) +#define AIC32X4_LORGAIN AIC32X4_REG(1, 19) +#define AIC32X4_HEADSTART AIC32X4_REG(1, 20) +#define AIC32X4_MICBIAS AIC32X4_REG(1, 51) +#define AIC32X4_LMICPGAPIN AIC32X4_REG(1, 52) +#define AIC32X4_LMICPGANIN AIC32X4_REG(1, 54) +#define AIC32X4_RMICPGAPIN AIC32X4_REG(1, 55) +#define AIC32X4_RMICPGANIN AIC32X4_REG(1, 57) +#define AIC32X4_FLOATINGINPUT AIC32X4_REG(1, 58) +#define AIC32X4_LMICPGAVOL AIC32X4_REG(1, 59) +#define AIC32X4_RMICPGAVOL AIC32X4_REG(1, 60) #define AIC32X4_FREQ_12000000 12000000 #define AIC32X4_FREQ_24000000 24000000 -- cgit v1.2.3 From 7e2a4dc5c1f0875646816c527cad5943cb6d5cc7 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 12 Dec 2017 16:43:04 -0600 Subject: ASoC: tlv320aic32x4: Drop define mapping from number to number Drop definition of frequencies that only map from one number to the same number. This is not needed and if misused can hide bugs. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 46 ++++++++++++++++++++-------------------- sound/soc/codecs/tlv320aic32x4.h | 4 ---- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index e694f5f04eb9..d7a67bfcc6d8 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -281,34 +281,34 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = { static const struct aic32x4_rate_divs aic32x4_divs[] = { /* 8k rate */ - {AIC32X4_FREQ_12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24}, - {AIC32X4_FREQ_24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24}, - {AIC32X4_FREQ_25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24}, + {12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24}, + {24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24}, + {25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24}, /* 11.025k rate */ - {AIC32X4_FREQ_12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16}, - {AIC32X4_FREQ_24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16}, + {12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16}, + {24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16}, /* 16k rate */ - {AIC32X4_FREQ_12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12}, - {AIC32X4_FREQ_24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12}, - {AIC32X4_FREQ_25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12}, + {12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12}, + {24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12}, + {25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12}, /* 22.05k rate */ - {AIC32X4_FREQ_12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8}, - {AIC32X4_FREQ_24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8}, - {AIC32X4_FREQ_25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8}, + {12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8}, + {24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8}, + {25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8}, /* 32k rate */ - {AIC32X4_FREQ_12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6}, - {AIC32X4_FREQ_24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6}, + {12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6}, + {24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6}, /* 44.1k rate */ - {AIC32X4_FREQ_12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4}, - {AIC32X4_FREQ_24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4}, - {AIC32X4_FREQ_25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4}, + {12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4}, + {24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4}, + {25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4}, /* 48k rate */ - {AIC32X4_FREQ_12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4}, - {AIC32X4_FREQ_24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4}, - {AIC32X4_FREQ_25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4}, + {12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4}, + {24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4}, + {25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4}, /* 96k rate */ - {AIC32X4_FREQ_25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1}, + {25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1}, }; static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { @@ -601,9 +601,9 @@ static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai, struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); switch (freq) { - case AIC32X4_FREQ_12000000: - case AIC32X4_FREQ_24000000: - case AIC32X4_FREQ_25000000: + case 12000000: + case 24000000: + case 25000000: aic32x4->sysclk = freq; return 0; } diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index 936bb7a1b5c8..b017211f83eb 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -97,10 +97,6 @@ int aic32x4_remove(struct device *dev); #define AIC32X4_LMICPGAVOL AIC32X4_REG(1, 59) #define AIC32X4_RMICPGAVOL AIC32X4_REG(1, 60) -#define AIC32X4_FREQ_12000000 12000000 -#define AIC32X4_FREQ_24000000 24000000 -#define AIC32X4_FREQ_25000000 25000000 - #define AIC32X4_WORD_LEN_16BITS 0x00 #define AIC32X4_WORD_LEN_20BITS 0x01 #define AIC32X4_WORD_LEN_24BITS 0x02 -- cgit v1.2.3 From 4483521d81684764cb7f2569bf3e4b10d38ef9f7 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 12 Dec 2017 16:43:05 -0600 Subject: ASoC: tlv320aic32x4: Use correct shift definition for DATATYPE bits Setting the DATATYPE bit field requires shifting our value by 6. Setting the J value of the PLL also requires a shift by 6. Currently the code abuses this fact and uses the shift for the PLL register to set the data-type register. Fix this here by using the definition meant for this register. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index d7a67bfcc6d8..8f9719e6cdfd 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -641,21 +641,23 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) case SND_SOC_DAIFMT_I2S: break; case SND_SOC_DAIFMT_DSP_A: - iface_reg_1 |= (AIC32X4_DSP_MODE << AIC32X4_PLLJ_SHIFT); + iface_reg_1 |= (AIC32X4_DSP_MODE << + AIC32X4_IFACE1_DATATYPE_SHIFT); iface_reg_3 |= (1 << 3); /* invert bit clock */ iface_reg_2 = 0x01; /* add offset 1 */ break; case SND_SOC_DAIFMT_DSP_B: - iface_reg_1 |= (AIC32X4_DSP_MODE << AIC32X4_PLLJ_SHIFT); + iface_reg_1 |= (AIC32X4_DSP_MODE << + AIC32X4_IFACE1_DATATYPE_SHIFT); iface_reg_3 |= (1 << 3); /* invert bit clock */ break; case SND_SOC_DAIFMT_RIGHT_J: - iface_reg_1 |= - (AIC32X4_RIGHT_JUSTIFIED_MODE << AIC32X4_PLLJ_SHIFT); + iface_reg_1 |= (AIC32X4_RIGHT_JUSTIFIED_MODE << + AIC32X4_IFACE1_DATATYPE_SHIFT); break; case SND_SOC_DAIFMT_LEFT_J: - iface_reg_1 |= - (AIC32X4_LEFT_JUSTIFIED_MODE << AIC32X4_PLLJ_SHIFT); + iface_reg_1 |= (AIC32X4_LEFT_JUSTIFIED_MODE << + AIC32X4_IFACE1_DATATYPE_SHIFT); break; default: printk(KERN_ERR "aic32x4: invalid DAI interface format\n"); -- cgit v1.2.3 From 77bdb58795d86262e96ba37524489ba0969de253 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 12 Dec 2017 16:43:06 -0600 Subject: ASoC: tlv320aic32x4: Use correct shift definition for DATALEN bits Setting the DATALEN bit field requires shifting our value by 4. Setting the OSR value of the PLL divider also requires a shift by 4. Currently the code abuses this fact and uses the shift for the divider register to set the data-length register. Fix this here by using the definition meant for this register. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 8f9719e6cdfd..9f643199e1ba 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -738,15 +738,20 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, data = data & ~(3 << 4); switch (params_width(params)) { case 16: + data |= (AIC32X4_WORD_LEN_16BITS << + AIC32X4_IFACE1_DATALEN_SHIFT); break; case 20: - data |= (AIC32X4_WORD_LEN_20BITS << AIC32X4_DOSRMSB_SHIFT); + data |= (AIC32X4_WORD_LEN_20BITS << + AIC32X4_IFACE1_DATALEN_SHIFT); break; case 24: - data |= (AIC32X4_WORD_LEN_24BITS << AIC32X4_DOSRMSB_SHIFT); + data |= (AIC32X4_WORD_LEN_24BITS << + AIC32X4_IFACE1_DATALEN_SHIFT); break; case 32: - data |= (AIC32X4_WORD_LEN_32BITS << AIC32X4_DOSRMSB_SHIFT); + data |= (AIC32X4_WORD_LEN_32BITS << + AIC32X4_IFACE1_DATALEN_SHIFT); break; } snd_soc_write(codec, AIC32X4_IFACE1, data); -- cgit v1.2.3 From 0fe7aa39ba0492aabdde67dc1511055c9dc7e960 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 12 Dec 2017 16:43:07 -0600 Subject: ASoC: tlv320aic32x4: Use BIT and GENMASK for bit field definitions Inter-register definitions should use BIT and GENMASK definitions and also be grouped by what register they belong to. This makes it easy to cross-check with the datasheet and is consistent with other drivers. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 2 +- sound/soc/codecs/tlv320aic32x4.h | 132 ++++++++++++++++++++++++++------------- 2 files changed, 88 insertions(+), 46 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 9f643199e1ba..e528a8495346 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -686,7 +686,7 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, } /* Use PLL as CODEC_CLKIN and DAC_MOD_CLK as BDIV_CLKIN */ - snd_soc_write(codec, AIC32X4_CLKMUX, AIC32X4_PLLCLKIN); + snd_soc_write(codec, AIC32X4_CLKMUX, AIC32X4_CODEC_CLKIN_PLL); snd_soc_write(codec, AIC32X4_IFACE3, AIC32X4_DACMOD2BCLK); /* We will fix R value to 1 and will make P & J=K.D as varialble */ diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index b017211f83eb..67772e5585b8 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -97,61 +97,103 @@ int aic32x4_remove(struct device *dev); #define AIC32X4_LMICPGAVOL AIC32X4_REG(1, 59) #define AIC32X4_RMICPGAVOL AIC32X4_REG(1, 60) -#define AIC32X4_WORD_LEN_16BITS 0x00 -#define AIC32X4_WORD_LEN_20BITS 0x01 -#define AIC32X4_WORD_LEN_24BITS 0x02 -#define AIC32X4_WORD_LEN_32BITS 0x03 - -#define AIC32X4_LADC_EN (1 << 7) -#define AIC32X4_RADC_EN (1 << 6) - -#define AIC32X4_I2S_MODE 0x00 -#define AIC32X4_DSP_MODE 0x01 -#define AIC32X4_RIGHT_JUSTIFIED_MODE 0x02 -#define AIC32X4_LEFT_JUSTIFIED_MODE 0x03 - -#define AIC32X4_AVDDWEAKDISABLE 0x08 -#define AIC32X4_LDOCTLEN 0x01 +/* Bits, masks, and shifts */ + +/* AIC32X4_CLKMUX */ +#define AIC32X4_PLL_CLKIN_MASK GENMASK(3, 2) +#define AIC32X4_PLL_CLKIN_SHIFT (2) +#define AIC32X4_PLL_CLKIN_MCLK (0x00) +#define AIC32X4_PLL_CLKIN_BCKL (0x01) +#define AIC32X4_PLL_CLKIN_GPIO1 (0x02) +#define AIC32X4_PLL_CLKIN_DIN (0x03) +#define AIC32X4_CODEC_CLKIN_MASK GENMASK(1, 0) +#define AIC32X4_CODEC_CLKIN_SHIFT (0) +#define AIC32X4_CODEC_CLKIN_MCLK (0x00) +#define AIC32X4_CODEC_CLKIN_BCLK (0x01) +#define AIC32X4_CODEC_CLKIN_GPIO1 (0x02) +#define AIC32X4_CODEC_CLKIN_PLL (0x03) + +/* AIC32X4_PLLPR */ +#define AIC32X4_PLLEN BIT(7) + +/* AIC32X4_NDAC */ +#define AIC32X4_NDACEN BIT(7) + +/* AIC32X4_MDAC */ +#define AIC32X4_MDACEN BIT(7) + +/* AIC32X4_NADC */ +#define AIC32X4_NADCEN BIT(7) + +/* AIC32X4_MADC */ +#define AIC32X4_MADCEN BIT(7) + +/* AIC32X4_BCLKN */ +#define AIC32X4_BCLKEN BIT(7) + +/* AIC32X4_IFACE1 */ +#define AIC32X4_IFACE1_DATATYPE_MASK GENMASK(7, 6) +#define AIC32X4_IFACE1_DATATYPE_SHIFT (6) +#define AIC32X4_I2S_MODE (0x00) +#define AIC32X4_DSP_MODE (0x01) +#define AIC32X4_RIGHT_JUSTIFIED_MODE (0x02) +#define AIC32X4_LEFT_JUSTIFIED_MODE (0x03) +#define AIC32X4_IFACE1_DATALEN_MASK GENMASK(5, 4) +#define AIC32X4_IFACE1_DATALEN_SHIFT (4) +#define AIC32X4_WORD_LEN_16BITS (0x00) +#define AIC32X4_WORD_LEN_20BITS (0x01) +#define AIC32X4_WORD_LEN_24BITS (0x02) +#define AIC32X4_WORD_LEN_32BITS (0x03) +#define AIC32X4_IFACE1_MASTER_MASK GENMASK(3, 2) +#define AIC32X4_BCLKMASTER BIT(2) +#define AIC32X4_WCLKMASTER BIT(3) + +/* AIC32X4_IFACE2 */ +#define AIC32X4_DATA_OFFSET_MASK GENMASK(7, 0) + +/* AIC32X4_IFACE3 */ +#define AIC32X4_BCLKINV_MASK BIT(3) +#define AIC32X4_BDIVCLK_MASK GENMASK(1, 0) +#define AIC32X4_BDIVCLK_SHIFT (0) +#define AIC32X4_DAC2BCLK (0x00) +#define AIC32X4_DACMOD2BCLK (0x01) +#define AIC32X4_ADC2BCLK (0x02) +#define AIC32X4_ADCMOD2BCLK (0x03) + +/* AIC32X4_DACSETUP */ +#define AIC32X4_DAC_CHAN_MASK GENMASK(5, 2) +#define AIC32X4_LDAC2RCHN BIT(5) +#define AIC32X4_LDAC2LCHN BIT(4) +#define AIC32X4_RDAC2LCHN BIT(3) +#define AIC32X4_RDAC2RCHN BIT(2) + +/* AIC32X4_DACMUTE */ +#define AIC32X4_MUTEON 0x0C -#define AIC32X4_LDOIN_18_36 0x01 -#define AIC32X4_LDOIN2HP 0x02 +/* AIC32X4_ADCSETUP */ +#define AIC32X4_LADC_EN BIT(7) +#define AIC32X4_RADC_EN BIT(6) -#define AIC32X4_DACSPBLOCK_MASK 0x1f -#define AIC32X4_ADCSPBLOCK_MASK 0x1f +/* AIC32X4_PWRCFG */ +#define AIC32X4_AVDDWEAKDISABLE BIT(3) -#define AIC32X4_PLLJ_SHIFT 6 -#define AIC32X4_DOSRMSB_SHIFT 4 +/* AIC32X4_LDOCTL */ +#define AIC32X4_LDOCTLEN BIT(0) -#define AIC32X4_PLLCLKIN 0x03 +/* AIC32X4_CMMODE */ +#define AIC32X4_LDOIN_18_36 BIT(0) +#define AIC32X4_LDOIN2HP BIT(1) -#define AIC32X4_MICBIAS_LDOIN 0x08 +/* AIC32X4_MICBIAS */ +#define AIC32X4_MICBIAS_LDOIN BIT(3) #define AIC32X4_MICBIAS_2075V 0x60 +/* AIC32X4_LMICPGANIN */ #define AIC32X4_LMICPGANIN_IN2R_10K 0x10 #define AIC32X4_LMICPGANIN_CM1L_10K 0x40 + +/* AIC32X4_RMICPGANIN */ #define AIC32X4_RMICPGANIN_IN1L_10K 0x10 #define AIC32X4_RMICPGANIN_CM1R_10K 0x40 -#define AIC32X4_LMICPGAVOL_NOGAIN 0x80 -#define AIC32X4_RMICPGAVOL_NOGAIN 0x80 - -#define AIC32X4_BCLKMASTER 0x08 -#define AIC32X4_WCLKMASTER 0x04 -#define AIC32X4_PLLEN (0x01 << 7) -#define AIC32X4_NDACEN (0x01 << 7) -#define AIC32X4_MDACEN (0x01 << 7) -#define AIC32X4_NADCEN (0x01 << 7) -#define AIC32X4_MADCEN (0x01 << 7) -#define AIC32X4_BCLKEN (0x01 << 7) -#define AIC32X4_DACEN (0x03 << 6) -#define AIC32X4_RDAC2LCHN (0x02 << 2) -#define AIC32X4_LDAC2RCHN (0x02 << 4) -#define AIC32X4_LDAC2LCHN (0x01 << 4) -#define AIC32X4_RDAC2RCHN (0x01 << 2) -#define AIC32X4_DAC_CHAN_MASK 0x3c - -#define AIC32X4_SSTEP2WCLK 0x01 -#define AIC32X4_MUTEON 0x0C -#define AIC32X4_DACMOD2BCLK 0x01 - #endif /* _TLV320AIC32X4_H */ -- cgit v1.2.3 From b7ddd9cab7d1c800db83e442e881d8cb3f755633 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 12 Dec 2017 16:43:08 -0600 Subject: ASoC: tlv320aic32x4: Use snd_soc_update_bits() in aic32x4_mute() Simplify mute function by using snd_soc_update_bits() over read/modify/write style code. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index e528a8495346..5deabe36ae94 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -773,13 +773,10 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, static int aic32x4_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u8 dac_reg; - dac_reg = snd_soc_read(codec, AIC32X4_DACMUTE) & ~AIC32X4_MUTEON; - if (mute) - snd_soc_write(codec, AIC32X4_DACMUTE, dac_reg | AIC32X4_MUTEON); - else - snd_soc_write(codec, AIC32X4_DACMUTE, dac_reg); + snd_soc_update_bits(codec, AIC32X4_DACMUTE, + AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0); + return 0; } -- cgit v1.2.3 From 64aab89974ebddf4cc67e4ed8996d879a9d054b9 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 12 Dec 2017 16:43:09 -0600 Subject: ASoC: tlv320aic32x4: Use snd_soc_update_bits() in aic32x4_hw_params() Make the code easier to read by using snd_soc_update_bits() over read/modify/write sequences. Also use separate per-register variables instead of re-using "data". This can prevent accidental over-writing and makes it clear for which register each bit value is intended. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 90 ++++++++++++++++++++-------------------- sound/soc/codecs/tlv320aic32x4.h | 8 ++++ 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 5deabe36ae94..63a52cdb7afe 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -676,7 +676,8 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); - u8 data; + u8 iface1_reg = 0; + u8 dacsetup_reg = 0; int i; i = aic32x4_get_divs(aic32x4->sysclk, params_rate(params)); @@ -685,87 +686,88 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, return i; } - /* Use PLL as CODEC_CLKIN and DAC_MOD_CLK as BDIV_CLKIN */ - snd_soc_write(codec, AIC32X4_CLKMUX, AIC32X4_CODEC_CLKIN_PLL); - snd_soc_write(codec, AIC32X4_IFACE3, AIC32X4_DACMOD2BCLK); + /* MCLK as PLL_CLKIN */ + snd_soc_update_bits(codec, AIC32X4_CLKMUX, AIC32X4_PLL_CLKIN_MASK, + AIC32X4_PLL_CLKIN_MCLK << AIC32X4_PLL_CLKIN_SHIFT); + /* PLL as CODEC_CLKIN */ + snd_soc_update_bits(codec, AIC32X4_CLKMUX, AIC32X4_CODEC_CLKIN_MASK, + AIC32X4_CODEC_CLKIN_PLL << AIC32X4_CODEC_CLKIN_SHIFT); + /* DAC_MOD_CLK as BDIV_CLKIN */ + snd_soc_update_bits(codec, AIC32X4_IFACE3, AIC32X4_BDIVCLK_MASK, + AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT); - /* We will fix R value to 1 and will make P & J=K.D as varialble */ - data = snd_soc_read(codec, AIC32X4_PLLPR); - data &= ~(7 << 4); - snd_soc_write(codec, AIC32X4_PLLPR, - (data | (aic32x4_divs[i].p_val << 4) | 0x01)); + /* We will fix R value to 1 and will make P & J=K.D as variable */ + snd_soc_update_bits(codec, AIC32X4_PLLPR, AIC32X4_PLL_R_MASK, 0x01); + /* PLL P value */ + snd_soc_update_bits(codec, AIC32X4_PLLPR, AIC32X4_PLL_P_MASK, + aic32x4_divs[i].p_val << AIC32X4_PLL_P_SHIFT); + + /* PLL J value */ snd_soc_write(codec, AIC32X4_PLLJ, aic32x4_divs[i].pll_j); + /* PLL D value */ snd_soc_write(codec, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8)); - snd_soc_write(codec, AIC32X4_PLLDLSB, - (aic32x4_divs[i].pll_d & 0xff)); + snd_soc_write(codec, AIC32X4_PLLDLSB, (aic32x4_divs[i].pll_d & 0xff)); /* NDAC divider value */ - data = snd_soc_read(codec, AIC32X4_NDAC); - data &= ~(0x7f); - snd_soc_write(codec, AIC32X4_NDAC, data | aic32x4_divs[i].ndac); + snd_soc_update_bits(codec, AIC32X4_NDAC, + AIC32X4_NDAC_MASK, aic32x4_divs[i].ndac); /* MDAC divider value */ - data = snd_soc_read(codec, AIC32X4_MDAC); - data &= ~(0x7f); - snd_soc_write(codec, AIC32X4_MDAC, data | aic32x4_divs[i].mdac); + snd_soc_update_bits(codec, AIC32X4_MDAC, + AIC32X4_MDAC_MASK, aic32x4_divs[i].mdac); /* DOSR MSB & LSB values */ snd_soc_write(codec, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8); - snd_soc_write(codec, AIC32X4_DOSRLSB, - (aic32x4_divs[i].dosr & 0xff)); + snd_soc_write(codec, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff)); /* NADC divider value */ - data = snd_soc_read(codec, AIC32X4_NADC); - data &= ~(0x7f); - snd_soc_write(codec, AIC32X4_NADC, data | aic32x4_divs[i].nadc); + snd_soc_update_bits(codec, AIC32X4_NADC, + AIC32X4_NADC_MASK, aic32x4_divs[i].nadc); /* MADC divider value */ - data = snd_soc_read(codec, AIC32X4_MADC); - data &= ~(0x7f); - snd_soc_write(codec, AIC32X4_MADC, data | aic32x4_divs[i].madc); + snd_soc_update_bits(codec, AIC32X4_MADC, + AIC32X4_MADC_MASK, aic32x4_divs[i].madc); /* AOSR value */ snd_soc_write(codec, AIC32X4_AOSR, aic32x4_divs[i].aosr); /* BCLK N divider */ - data = snd_soc_read(codec, AIC32X4_BCLKN); - data &= ~(0x7f); - snd_soc_write(codec, AIC32X4_BCLKN, data | aic32x4_divs[i].blck_N); + snd_soc_update_bits(codec, AIC32X4_BCLKN, + AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N); - data = snd_soc_read(codec, AIC32X4_IFACE1); - data = data & ~(3 << 4); switch (params_width(params)) { case 16: - data |= (AIC32X4_WORD_LEN_16BITS << - AIC32X4_IFACE1_DATALEN_SHIFT); + iface1_reg |= (AIC32X4_WORD_LEN_16BITS << + AIC32X4_IFACE1_DATALEN_SHIFT); break; case 20: - data |= (AIC32X4_WORD_LEN_20BITS << - AIC32X4_IFACE1_DATALEN_SHIFT); + iface1_reg |= (AIC32X4_WORD_LEN_20BITS << + AIC32X4_IFACE1_DATALEN_SHIFT); break; case 24: - data |= (AIC32X4_WORD_LEN_24BITS << - AIC32X4_IFACE1_DATALEN_SHIFT); + iface1_reg |= (AIC32X4_WORD_LEN_24BITS << + AIC32X4_IFACE1_DATALEN_SHIFT); break; case 32: - data |= (AIC32X4_WORD_LEN_32BITS << - AIC32X4_IFACE1_DATALEN_SHIFT); + iface1_reg |= (AIC32X4_WORD_LEN_32BITS << + AIC32X4_IFACE1_DATALEN_SHIFT); break; } - snd_soc_write(codec, AIC32X4_IFACE1, data); + snd_soc_update_bits(codec, AIC32X4_IFACE1, + AIC32X4_IFACE1_DATALEN_MASK, iface1_reg); if (params_channels(params) == 1) { - data = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN; + dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN; } else { if (aic32x4->swapdacs) - data = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN; + dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN; else - data = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN; + dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN; } - snd_soc_update_bits(codec, AIC32X4_DACSETUP, AIC32X4_DAC_CHAN_MASK, - data); + snd_soc_update_bits(codec, AIC32X4_DACSETUP, + AIC32X4_DAC_CHAN_MASK, dacsetup_reg); return 0; } diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index 67772e5585b8..e9df49edbf19 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -115,21 +115,29 @@ int aic32x4_remove(struct device *dev); /* AIC32X4_PLLPR */ #define AIC32X4_PLLEN BIT(7) +#define AIC32X4_PLL_P_MASK GENMASK(6, 4) +#define AIC32X4_PLL_P_SHIFT (4) +#define AIC32X4_PLL_R_MASK GENMASK(3, 0) /* AIC32X4_NDAC */ #define AIC32X4_NDACEN BIT(7) +#define AIC32X4_NDAC_MASK GENMASK(6, 0) /* AIC32X4_MDAC */ #define AIC32X4_MDACEN BIT(7) +#define AIC32X4_MDAC_MASK GENMASK(6, 0) /* AIC32X4_NADC */ #define AIC32X4_NADCEN BIT(7) +#define AIC32X4_NADC_MASK GENMASK(6, 0) /* AIC32X4_MADC */ #define AIC32X4_MADCEN BIT(7) +#define AIC32X4_MADC_MASK GENMASK(6, 0) /* AIC32X4_BCLKN */ #define AIC32X4_BCLKEN BIT(7) +#define AIC32X4_BCLK_MASK GENMASK(6, 0) /* AIC32X4_IFACE1 */ #define AIC32X4_IFACE1_DATATYPE_MASK GENMASK(7, 6) -- cgit v1.2.3 From 60fb4be565c9c44f6999aaa9d18808f1ac49d6ef Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 12 Dec 2017 16:43:10 -0600 Subject: ASoC: tlv320aic32x4: Use snd_soc_update_bits() in aic32x4_set_dai_fmt() Make the code easier to read by using snd_soc_update_bits() over read/modify/write sequences. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 63a52cdb7afe..fea019343c3b 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -614,16 +614,9 @@ static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai, static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; - u8 iface_reg_1; - u8 iface_reg_2; - u8 iface_reg_3; - - iface_reg_1 = snd_soc_read(codec, AIC32X4_IFACE1); - iface_reg_1 = iface_reg_1 & ~(3 << 6 | 3 << 2); - iface_reg_2 = snd_soc_read(codec, AIC32X4_IFACE2); - iface_reg_2 = 0; - iface_reg_3 = snd_soc_read(codec, AIC32X4_IFACE3); - iface_reg_3 = iface_reg_3 & ~(1 << 3); + u8 iface_reg_1 = 0; + u8 iface_reg_2 = 0; + u8 iface_reg_3 = 0; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -643,13 +636,13 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) case SND_SOC_DAIFMT_DSP_A: iface_reg_1 |= (AIC32X4_DSP_MODE << AIC32X4_IFACE1_DATATYPE_SHIFT); - iface_reg_3 |= (1 << 3); /* invert bit clock */ + iface_reg_3 |= AIC32X4_BCLKINV_MASK; /* invert bit clock */ iface_reg_2 = 0x01; /* add offset 1 */ break; case SND_SOC_DAIFMT_DSP_B: iface_reg_1 |= (AIC32X4_DSP_MODE << AIC32X4_IFACE1_DATATYPE_SHIFT); - iface_reg_3 |= (1 << 3); /* invert bit clock */ + iface_reg_3 |= AIC32X4_BCLKINV_MASK; /* invert bit clock */ break; case SND_SOC_DAIFMT_RIGHT_J: iface_reg_1 |= (AIC32X4_RIGHT_JUSTIFIED_MODE << @@ -664,9 +657,14 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } - snd_soc_write(codec, AIC32X4_IFACE1, iface_reg_1); - snd_soc_write(codec, AIC32X4_IFACE2, iface_reg_2); - snd_soc_write(codec, AIC32X4_IFACE3, iface_reg_3); + snd_soc_update_bits(codec, AIC32X4_IFACE1, + AIC32X4_IFACE1_DATATYPE_MASK | + AIC32X4_IFACE1_MASTER_MASK, iface_reg_1); + snd_soc_update_bits(codec, AIC32X4_IFACE2, + AIC32X4_DATA_OFFSET_MASK, iface_reg_2); + snd_soc_update_bits(codec, AIC32X4_IFACE3, + AIC32X4_BCLKINV_MASK, iface_reg_3); + return 0; } -- cgit v1.2.3 From 9245f647fc7b82b88587b2d1de02fae66d2d314e Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 12 Dec 2017 16:43:11 -0600 Subject: ASoC: tlv320aic32x4: Make driver selectable in Kconfig Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a42ddbc93f3d..7780dcf02f99 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -913,12 +913,12 @@ config SND_SOC_TLV320AIC32X4 tristate config SND_SOC_TLV320AIC32X4_I2C - tristate + tristate "Texas Instruments TLV320AIC32x4 audio CODECs - I2C" depends on I2C select SND_SOC_TLV320AIC32X4 config SND_SOC_TLV320AIC32X4_SPI - tristate + tristate "Texas Instruments TLV320AIC32x4 audio CODECs - SPI" depends on SPI_MASTER select SND_SOC_TLV320AIC32X4 -- cgit v1.2.3 From 2ff739b9bdd3199cd52e450097cb0f7fc4e1e9e8 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 14 Dec 2017 15:29:28 +0800 Subject: ASoC: sun4i-i2s: Show detailed error when DAI configuration callbacks fail When any of the DAI hardware configuration callbacks (.hw_param, .set_fmt, .set_sysclk) fails, there is no explanation about why it failed. This is particularly confusing for .hw_param, which covers many parameters of the DAI. Telling the users what parameter isn't supported, and what the requested value was goes a long way for developers trying to combine sun4i-i2s with external codecs. This patch adds dev_err calls explaining what isn't supported or failed, and what the value was. sun4i_i2s_set_clk_rate()'s first parameter was changed to a struct snd_soc_dai *dai, so we can get the underlying device. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Acked-by: Marcus Cooper Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 04f92583a969..bc147e2dcff5 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -269,10 +269,11 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample) return false; } -static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s, +static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, unsigned int rate, unsigned int word_size) { + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); unsigned int oversample_rate, clk_rate; int bclk_div, mclk_div; int ret; @@ -300,6 +301,7 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s, break; default: + dev_err(dai->dev, "Unsupported sample rate: %u\n", rate); return -EINVAL; } @@ -308,18 +310,25 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s, return ret; oversample_rate = i2s->mclk_freq / rate; - if (!sun4i_i2s_oversample_is_valid(oversample_rate)) + if (!sun4i_i2s_oversample_is_valid(oversample_rate)) { + dev_err(dai->dev, "Unsupported oversample rate: %d\n", + oversample_rate); return -EINVAL; + } bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate, word_size); - if (bclk_div < 0) + if (bclk_div < 0) { + dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); return -EINVAL; + } mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate, clk_rate, rate); - if (mclk_div < 0) + if (mclk_div < 0) { + dev_err(dai->dev, "Unsupported MCLK divider: %d\n", mclk_div); return -EINVAL; + } /* Adjust the clock division values if needed */ bclk_div += i2s->variant->bclk_offset; @@ -349,8 +358,11 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, u32 width; channels = params_channels(params); - if (channels != 2) + if (channels != 2) { + dev_err(dai->dev, "Unsupported number of channels: %d\n", + channels); return -EINVAL; + } if (i2s->variant->has_chcfg) { regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, @@ -382,6 +394,8 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, width = DMA_SLAVE_BUSWIDTH_2_BYTES; break; default: + dev_err(dai->dev, "Unsupported physical sample width: %d\n", + params_physical_width(params)); return -EINVAL; } i2s->playback_dma_data.addr_width = width; @@ -393,6 +407,8 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, break; default: + dev_err(dai->dev, "Unsupported sample width: %d\n", + params_width(params)); return -EINVAL; } @@ -401,7 +417,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, regmap_field_write(i2s->field_fmt_sr, sr + i2s->variant->fmt_offset); - return sun4i_i2s_set_clk_rate(i2s, params_rate(params), + return sun4i_i2s_set_clk_rate(dai, params_rate(params), params_width(params)); } @@ -426,6 +442,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) val = SUN4I_I2S_FMT0_FMT_RIGHT_J; break; default: + dev_err(dai->dev, "Unsupported format: %d\n", + fmt & SND_SOC_DAIFMT_FORMAT_MASK); return -EINVAL; } @@ -464,6 +482,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) case SND_SOC_DAIFMT_NB_NF: break; default: + dev_err(dai->dev, "Unsupported clock polarity: %d\n", + fmt & SND_SOC_DAIFMT_INV_MASK); return -EINVAL; } @@ -482,6 +502,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) val = SUN4I_I2S_CTRL_MODE_SLAVE; break; default: + dev_err(dai->dev, "Unsupported slave setting: %d\n", + fmt & SND_SOC_DAIFMT_MASTER_MASK); return -EINVAL; } regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, @@ -504,6 +526,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) val = 0; break; default: + dev_err(dai->dev, "Unsupported slave setting: %d\n", + fmt & SND_SOC_DAIFMT_MASTER_MASK); return -EINVAL; } regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, -- cgit v1.2.3 From cb2cf0de1174701b7c8c0285a0f398b9f2d30d8e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 15 Dec 2017 05:10:47 +0000 Subject: ASoC: soc-core: care Codec <-> Codec case by non_legacy_dai_naming CPU/Codec categorize will be removed soon. Then, it need to know DAI is Codec somehow. This patch uses component driver's "non_legacy_dai_naming" which is used by Codec for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 90f1122d91c4..b9ca939fd05c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1945,7 +1945,9 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, } /* Flip the polarity for the "CPU" end of a CODEC<->CODEC link */ - if (cpu_dai->codec) { + /* the component which has non_legacy_dai_naming is Codec */ + if (cpu_dai->codec || + cpu_dai->component->driver->non_legacy_dai_naming) { unsigned int inv_dai_fmt; inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_MASTER_MASK; -- cgit v1.2.3 From f31768349447cdf975abbcb7d4a18c0b5d4971c3 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sun, 17 Dec 2017 18:52:00 -0800 Subject: ASoC: fsl_ssi: Rename fsl_ssi_private to fsl_ssi Shorten the private data structure to save some wrapped lines. Signed-off-by: Nicolin Chen Tested-by: Maciej S. Szmigiero Reviewed-by: Maciej S. Szmigiero Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 456 +++++++++++++++++++++++------------------------- 1 file changed, 220 insertions(+), 236 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index c350117c8e31..84d2f7ecb5e1 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -185,7 +185,7 @@ struct fsl_ssi_soc_data { }; /** - * fsl_ssi_private: per-SSI private data + * fsl_ssi: per-SSI private data * * @reg: Pointer to the regmap registers * @irq: IRQ of this SSI @@ -224,7 +224,7 @@ struct fsl_ssi_soc_data { * @dma_maxburst: max number of words to transfer in one go. So far, * this is always the same as fifo_watermark. */ -struct fsl_ssi_private { +struct fsl_ssi { struct regmap *regs; int irq; struct snd_soc_dai_driver cpu_dai_drv; @@ -325,21 +325,21 @@ static const struct of_device_id fsl_ssi_ids[] = { }; MODULE_DEVICE_TABLE(of, fsl_ssi_ids); -static bool fsl_ssi_is_ac97(struct fsl_ssi_private *ssi_private) +static bool fsl_ssi_is_ac97(struct fsl_ssi *ssi) { - return (ssi_private->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) == + return (ssi->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_AC97; } -static bool fsl_ssi_is_i2s_master(struct fsl_ssi_private *ssi_private) +static bool fsl_ssi_is_i2s_master(struct fsl_ssi *ssi) { - return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == + return (ssi->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFS; } -static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private) +static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi *ssi) { - return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == + return (ssi->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFS; } /** @@ -352,12 +352,12 @@ static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private) * This interrupt handler is used only to gather statistics. * * @irq: IRQ of the SSI device - * @dev_id: pointer to the ssi_private structure for this SSI device + * @dev_id: pointer to the fsl_ssi structure for this SSI device */ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) { - struct fsl_ssi_private *ssi_private = dev_id; - struct regmap *regs = ssi_private->regs; + struct fsl_ssi *ssi = dev_id; + struct regmap *regs = ssi->regs; __be32 sisr; __be32 sisr2; @@ -367,12 +367,12 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) */ regmap_read(regs, CCSR_SSI_SISR, &sisr); - sisr2 = sisr & ssi_private->soc->sisr_write_mask; + sisr2 = sisr & ssi->soc->sisr_write_mask; /* Clear the bits that we set */ if (sisr2) regmap_write(regs, CCSR_SSI_SISR, sisr2); - fsl_ssi_dbg_isr(&ssi_private->dbg_stats, sisr); + fsl_ssi_dbg_isr(&ssi->dbg_stats, sisr); return IRQ_HANDLED; } @@ -380,11 +380,10 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) /* * Enable/Disable all rx/tx config flags at once. */ -static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private, - bool enable) +static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) { - struct regmap *regs = ssi_private->regs; - struct fsl_ssi_rxtx_reg_val *vals = &ssi_private->rxtx_reg_val; + struct regmap *regs = ssi->regs; + struct fsl_ssi_rxtx_reg_val *vals = &ssi->rxtx_reg_val; if (enable) { regmap_update_bits(regs, CCSR_SSI_SIER, @@ -414,14 +413,13 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private, * Note: The SOR is not documented in recent IMX datasheet, but * is described in IMX51 reference manual at section 56.3.3.15. */ -static void fsl_ssi_fifo_clear(struct fsl_ssi_private *ssi_private, - bool is_rx) +static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) { if (is_rx) { - regmap_update_bits(ssi_private->regs, CCSR_SSI_SOR, + regmap_update_bits(ssi->regs, CCSR_SSI_SOR, CCSR_SSI_SOR_RX_CLR, CCSR_SSI_SOR_RX_CLR); } else { - regmap_update_bits(ssi_private->regs, CCSR_SSI_SOR, + regmap_update_bits(ssi->regs, CCSR_SSI_SOR, CCSR_SSI_SOR_TX_CLR, CCSR_SSI_SOR_TX_CLR); } } @@ -448,12 +446,12 @@ static void fsl_ssi_fifo_clear(struct fsl_ssi_private *ssi_private, /* * Enable/Disable a ssi configuration. You have to pass either - * ssi_private->rxtx_reg_val.rx or tx as vals parameter. + * ssi->rxtx_reg_val.rx or tx as vals parameter. */ -static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable, +static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, struct fsl_ssi_reg_val *vals) { - struct regmap *regs = ssi_private->regs; + struct regmap *regs = ssi->regs; struct fsl_ssi_reg_val *avals; int nr_active_streams; u32 scr_val; @@ -471,10 +469,10 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable, /* Find the other direction values rx or tx which we do not want to * modify */ - if (&ssi_private->rxtx_reg_val.rx == vals) - avals = &ssi_private->rxtx_reg_val.tx; + if (&ssi->rxtx_reg_val.rx == vals) + avals = &ssi->rxtx_reg_val.tx; else - avals = &ssi_private->rxtx_reg_val.rx; + avals = &ssi->rxtx_reg_val.rx; /* If vals should be disabled, start with disabling the unit */ if (!enable) { @@ -488,10 +486,10 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable, * reconfiguration, so we have to enable all necessary flags at once * even if we do not use them later (capture and playback configuration) */ - if (ssi_private->soc->offline_config) { + if (ssi->soc->offline_config) { if ((enable && !nr_active_streams) || (!enable && !keep_active)) - fsl_ssi_rxtx_config(ssi_private, enable); + fsl_ssi_rxtx_config(ssi, enable); goto config_done; } @@ -501,7 +499,7 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable, * (online configuration) */ if (enable) { - fsl_ssi_fifo_clear(ssi_private, vals->scr & CCSR_SSI_SCR_RE); + fsl_ssi_fifo_clear(ssi, vals->scr & CCSR_SSI_SCR_RE); regmap_update_bits(regs, CCSR_SSI_SRCR, vals->srcr, vals->srcr); regmap_update_bits(regs, CCSR_SSI_STCR, vals->stcr, vals->stcr); @@ -536,7 +534,7 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable, config_done: /* Enabling of subunits is done after configuration */ if (enable) { - if (ssi_private->use_dma && (vals->scr & CCSR_SSI_SCR_TE)) { + if (ssi->use_dma && (vals->scr & CCSR_SSI_SCR_TE)) { /* * Be sure the Tx FIFO is filled when TE is set. * Otherwise, there are some chances to start the @@ -563,7 +561,7 @@ config_done: break; } if (i == max_loop) { - dev_err(ssi_private->dev, + dev_err(ssi->dev, "Timeout waiting TX FIFO filling\n"); } } @@ -572,17 +570,17 @@ config_done: } -static void fsl_ssi_rx_config(struct fsl_ssi_private *ssi_private, bool enable) +static void fsl_ssi_rx_config(struct fsl_ssi *ssi, bool enable) { - fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.rx); + fsl_ssi_config(ssi, enable, &ssi->rxtx_reg_val.rx); } -static void fsl_ssi_tx_ac97_saccst_setup(struct fsl_ssi_private *ssi_private) +static void fsl_ssi_tx_ac97_saccst_setup(struct fsl_ssi *ssi) { - struct regmap *regs = ssi_private->regs; + struct regmap *regs = ssi->regs; /* no SACC{ST,EN,DIS} regs on imx21-class SSI */ - if (!ssi_private->soc->imx21regs) { + if (!ssi->soc->imx21regs) { /* * Note that these below aren't just normal registers. * They are a way to disable or enable bits in SACCST @@ -601,7 +599,7 @@ static void fsl_ssi_tx_ac97_saccst_setup(struct fsl_ssi_private *ssi_private) } } -static void fsl_ssi_tx_config(struct fsl_ssi_private *ssi_private, bool enable) +static void fsl_ssi_tx_config(struct fsl_ssi *ssi, bool enable) { /* * Why are we setting up SACCST everytime we are starting a @@ -622,10 +620,10 @@ static void fsl_ssi_tx_config(struct fsl_ssi_private *ssi_private, bool enable) * untrustworthy let's play safe here and make sure that no extra * slots are enabled every time a playback is started. */ - if (enable && fsl_ssi_is_ac97(ssi_private)) - fsl_ssi_tx_ac97_saccst_setup(ssi_private); + if (enable && fsl_ssi_is_ac97(ssi)) + fsl_ssi_tx_ac97_saccst_setup(ssi); - fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.tx); + fsl_ssi_config(ssi, enable, &ssi->rxtx_reg_val.tx); } /* @@ -633,9 +631,9 @@ static void fsl_ssi_tx_config(struct fsl_ssi_private *ssi_private, bool enable) * be used later in fsl_ssi_config to setup the streams without the need to * check for all different SSI modes. */ -static void fsl_ssi_setup_reg_vals(struct fsl_ssi_private *ssi_private) +static void fsl_ssi_setup_reg_vals(struct fsl_ssi *ssi) { - struct fsl_ssi_rxtx_reg_val *reg = &ssi_private->rxtx_reg_val; + struct fsl_ssi_rxtx_reg_val *reg = &ssi->rxtx_reg_val; reg->rx.sier = CCSR_SSI_SIER_RFF0_EN; reg->rx.srcr = CCSR_SSI_SRCR_RFEN0; @@ -644,12 +642,12 @@ static void fsl_ssi_setup_reg_vals(struct fsl_ssi_private *ssi_private) reg->tx.stcr = CCSR_SSI_STCR_TFEN0; reg->tx.scr = 0; - if (!fsl_ssi_is_ac97(ssi_private)) { + if (!fsl_ssi_is_ac97(ssi)) { reg->rx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE; reg->tx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE; } - if (ssi_private->use_dma) { + if (ssi->use_dma) { reg->rx.sier |= CCSR_SSI_SIER_RDMAE; reg->tx.sier |= CCSR_SSI_SIER_TDMAE; } else { @@ -661,9 +659,9 @@ static void fsl_ssi_setup_reg_vals(struct fsl_ssi_private *ssi_private) reg->tx.sier |= FSLSSI_SIER_DBG_TX_FLAGS; } -static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private) +static void fsl_ssi_setup_ac97(struct fsl_ssi *ssi) { - struct regmap *regs = ssi_private->regs; + struct regmap *regs = ssi->regs; /* * Setup the clock control register @@ -702,11 +700,10 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct fsl_ssi_private *ssi_private = - snd_soc_dai_get_drvdata(rtd->cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai); int ret; - ret = clk_prepare_enable(ssi_private->clk); + ret = clk_prepare_enable(ssi->clk); if (ret) return ret; @@ -715,7 +712,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, * task from fifo0, fifo1 would be neglected at the end of each * period. But SSI would still access fifo1 with an invalid data. */ - if (ssi_private->use_dual_fifo) + if (ssi->use_dual_fifo) snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2); @@ -730,10 +727,9 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct fsl_ssi_private *ssi_private = - snd_soc_dai_get_drvdata(rtd->cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai); - clk_disable_unprepare(ssi_private->clk); + clk_disable_unprepare(ssi->clk); } @@ -750,9 +746,9 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai, struct snd_pcm_hw_params *hw_params) { - struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); - struct regmap *regs = ssi_private->regs; - int synchronous = ssi_private->cpu_dai_drv.symmetric_rates, ret; + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct regmap *regs = ssi->regs; + int synchronous = ssi->cpu_dai_drv.symmetric_rates, ret; u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i; unsigned long clkrate, baudrate, tmprate; unsigned int slots = params_channels(hw_params); @@ -762,29 +758,29 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, bool baudclk_is_used; /* Override slots and slot_width if being specifically set... */ - if (ssi_private->slots) - slots = ssi_private->slots; + if (ssi->slots) + slots = ssi->slots; /* ...but keep 32 bits if slots is 2 -- I2S Master mode */ - if (ssi_private->slot_width && slots != 2) - slot_width = ssi_private->slot_width; + if (ssi->slot_width && slots != 2) + slot_width = ssi->slot_width; /* Generate bit clock based on the slot number and slot width */ freq = slots * slot_width * params_rate(hw_params); /* Don't apply it to any non-baudclk circumstance */ - if (IS_ERR(ssi_private->baudclk)) + if (IS_ERR(ssi->baudclk)) return -EINVAL; /* * Hardware limitation: The bclk rate must be * never greater than 1/5 IPG clock rate */ - if (freq * 5 > clk_get_rate(ssi_private->clk)) { + if (freq * 5 > clk_get_rate(ssi->clk)) { dev_err(cpu_dai->dev, "bitclk > ipgclk/5\n"); return -EINVAL; } - baudclk_is_used = ssi_private->baudclk_streams & ~(BIT(substream->stream)); + baudclk_is_used = ssi->baudclk_streams & ~(BIT(substream->stream)); /* It should be already enough to divide clock by setting pm alone */ psr = 0; @@ -796,9 +792,9 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, tmprate = freq * factor * (i + 1); if (baudclk_is_used) - clkrate = clk_get_rate(ssi_private->baudclk); + clkrate = clk_get_rate(ssi->baudclk); else - clkrate = clk_round_rate(ssi_private->baudclk, tmprate); + clkrate = clk_round_rate(ssi->baudclk, tmprate); clkrate /= factor; afreq = clkrate / (i + 1); @@ -844,7 +840,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, regmap_update_bits(regs, CCSR_SSI_SRCCR, mask, stccr); if (!baudclk_is_used) { - ret = clk_set_rate(ssi_private->baudclk, baudrate); + ret = clk_set_rate(ssi->baudclk, baudrate); if (ret) { dev_err(cpu_dai->dev, "failed to set baudclk rate\n"); return -EINVAL; @@ -870,8 +866,8 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai) { - struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); - struct regmap *regs = ssi_private->regs; + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct regmap *regs = ssi->regs; unsigned int channels = params_channels(hw_params); unsigned int sample_size = params_width(hw_params); u32 wl = CCSR_SSI_SxCCR_WL(sample_size); @@ -886,35 +882,35 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, * If we're in synchronous mode, and the SSI is already enabled, * then STCCR is already set properly. */ - if (enabled && ssi_private->cpu_dai_drv.symmetric_rates) + if (enabled && ssi->cpu_dai_drv.symmetric_rates) return 0; - if (fsl_ssi_is_i2s_master(ssi_private)) { + if (fsl_ssi_is_i2s_master(ssi)) { ret = fsl_ssi_set_bclk(substream, cpu_dai, hw_params); if (ret) return ret; /* Do not enable the clock if it is already enabled */ - if (!(ssi_private->baudclk_streams & BIT(substream->stream))) { - ret = clk_prepare_enable(ssi_private->baudclk); + if (!(ssi->baudclk_streams & BIT(substream->stream))) { + ret = clk_prepare_enable(ssi->baudclk); if (ret) return ret; - ssi_private->baudclk_streams |= BIT(substream->stream); + ssi->baudclk_streams |= BIT(substream->stream); } } - if (!fsl_ssi_is_ac97(ssi_private)) { + if (!fsl_ssi_is_ac97(ssi)) { u8 i2smode; /* * Switch to normal net mode in order to have a frame sync * signal every 32 bits instead of 16 bits */ - if (fsl_ssi_is_i2s_cbm_cfs(ssi_private) && sample_size == 16) + if (fsl_ssi_is_i2s_cbm_cfs(ssi) && sample_size == 16) i2smode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET; else - i2smode = ssi_private->i2s_mode; + i2smode = ssi->i2s_mode; regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK, @@ -933,7 +929,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, /* In synchronous mode, the SSI uses STCCR for capture */ if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) || - ssi_private->cpu_dai_drv.symmetric_rates) + ssi->cpu_dai_drv.symmetric_rates) regmap_update_bits(regs, CCSR_SSI_STCCR, CCSR_SSI_SxCCR_WL_MASK, wl); else @@ -947,34 +943,32 @@ static int fsl_ssi_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct fsl_ssi_private *ssi_private = - snd_soc_dai_get_drvdata(rtd->cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai); - if (fsl_ssi_is_i2s_master(ssi_private) && - ssi_private->baudclk_streams & BIT(substream->stream)) { - clk_disable_unprepare(ssi_private->baudclk); - ssi_private->baudclk_streams &= ~BIT(substream->stream); + if (fsl_ssi_is_i2s_master(ssi) && + ssi->baudclk_streams & BIT(substream->stream)) { + clk_disable_unprepare(ssi->baudclk); + ssi->baudclk_streams &= ~BIT(substream->stream); } return 0; } static int _fsl_ssi_set_dai_fmt(struct device *dev, - struct fsl_ssi_private *ssi_private, - unsigned int fmt) + struct fsl_ssi *ssi, unsigned int fmt) { - struct regmap *regs = ssi_private->regs; + struct regmap *regs = ssi->regs; u32 strcr = 0, stcr, srcr, scr, mask; u8 wm; - ssi_private->dai_fmt = fmt; + ssi->dai_fmt = fmt; - if (fsl_ssi_is_i2s_master(ssi_private) && IS_ERR(ssi_private->baudclk)) { + if (fsl_ssi_is_i2s_master(ssi) && IS_ERR(ssi->baudclk)) { dev_err(dev, "baudclk is missing which is necessary for master mode\n"); return -EINVAL; } - fsl_ssi_setup_reg_vals(ssi_private); + fsl_ssi_setup_reg_vals(ssi); regmap_read(regs, CCSR_SSI_SCR, &scr); scr &= ~(CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_I2S_MODE_MASK); @@ -988,7 +982,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, stcr &= ~mask; srcr &= ~mask; - ssi_private->i2s_mode = CCSR_SSI_SCR_NET; + ssi->i2s_mode = CCSR_SSI_SCR_NET; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: regmap_update_bits(regs, CCSR_SSI_STCCR, @@ -1000,10 +994,10 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFS: case SND_SOC_DAIFMT_CBS_CFS: - ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER; + ssi->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER; break; case SND_SOC_DAIFMT_CBM_CFM: - ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_SLAVE; + ssi->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_SLAVE; break; default: return -EINVAL; @@ -1028,12 +1022,12 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, CCSR_SSI_STCR_TXBIT0; break; case SND_SOC_DAIFMT_AC97: - ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_NORMAL; + ssi->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_NORMAL; break; default: return -EINVAL; } - scr |= ssi_private->i2s_mode; + scr |= ssi->i2s_mode; /* DAI clock inversion */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -1072,15 +1066,14 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, scr &= ~CCSR_SSI_SCR_SYS_CLK_EN; break; default: - if (!fsl_ssi_is_ac97(ssi_private)) + if (!fsl_ssi_is_ac97(ssi)) return -EINVAL; } stcr |= strcr; srcr |= strcr; - if (ssi_private->cpu_dai_drv.symmetric_rates - || fsl_ssi_is_ac97(ssi_private)) { + if (ssi->cpu_dai_drv.symmetric_rates || fsl_ssi_is_ac97(ssi)) { /* Need to clear RXDIR when using SYNC or AC97 mode */ srcr &= ~CCSR_SSI_SRCR_RXDIR; scr |= CCSR_SSI_SCR_SYN; @@ -1090,13 +1083,13 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, regmap_write(regs, CCSR_SSI_SRCR, srcr); regmap_write(regs, CCSR_SSI_SCR, scr); - wm = ssi_private->fifo_watermark; + wm = ssi->fifo_watermark; regmap_write(regs, CCSR_SSI_SFCSR, CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) | CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm)); - if (ssi_private->use_dual_fifo) { + if (ssi->use_dual_fifo) { regmap_update_bits(regs, CCSR_SSI_SRCR, CCSR_SSI_SRCR_RFEN1, CCSR_SSI_SRCR_RFEN1); regmap_update_bits(regs, CCSR_SSI_STCR, CCSR_SSI_STCR_TFEN1, @@ -1106,7 +1099,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, } if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_AC97) - fsl_ssi_setup_ac97(ssi_private); + fsl_ssi_setup_ac97(ssi); return 0; @@ -1117,12 +1110,12 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, */ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { - struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); - if (fsl_ssi_is_ac97(ssi_private)) + if (fsl_ssi_is_ac97(ssi)) return 0; - return _fsl_ssi_set_dai_fmt(cpu_dai->dev, ssi_private, fmt); + return _fsl_ssi_set_dai_fmt(cpu_dai->dev, ssi, fmt); } /** @@ -1133,8 +1126,8 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, u32 rx_mask, int slots, int slot_width) { - struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); - struct regmap *regs = ssi_private->regs; + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct regmap *regs = ssi->regs; u32 val; /* The word length should be 8, 10, 12, 16, 18, 20, 22 or 24 */ @@ -1169,8 +1162,8 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN, val); - ssi_private->slot_width = slot_width; - ssi_private->slots = slots; + ssi->slot_width = slot_width; + ssi->slots = slots; return 0; } @@ -1188,33 +1181,33 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai); - struct regmap *regs = ssi_private->regs; + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai); + struct regmap *regs = ssi->regs; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - fsl_ssi_tx_config(ssi_private, true); + fsl_ssi_tx_config(ssi, true); else - fsl_ssi_rx_config(ssi_private, true); + fsl_ssi_rx_config(ssi, true); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - fsl_ssi_tx_config(ssi_private, false); + fsl_ssi_tx_config(ssi, false); else - fsl_ssi_rx_config(ssi_private, false); + fsl_ssi_rx_config(ssi, false); break; default: return -EINVAL; } - if (fsl_ssi_is_ac97(ssi_private)) { + if (fsl_ssi_is_ac97(ssi)) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) regmap_write(regs, CCSR_SSI_SOR, CCSR_SSI_SOR_TX_CLR); else @@ -1226,11 +1219,11 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, static int fsl_ssi_dai_probe(struct snd_soc_dai *dai) { - struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); - if (ssi_private->soc->imx && ssi_private->use_dma) { - dai->playback_dma_data = &ssi_private->dma_params_tx; - dai->capture_dma_data = &ssi_private->dma_params_rx; + if (ssi->soc->imx && ssi->use_dma) { + dai->playback_dma_data = &ssi->dma_params_tx; + dai->capture_dma_data = &ssi->dma_params_rx; } return 0; @@ -1292,7 +1285,7 @@ static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { }; -static struct fsl_ssi_private *fsl_ac97_data; +static struct fsl_ssi *fsl_ac97_data; static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) @@ -1383,24 +1376,24 @@ static void make_lowercase(char *s) } static int fsl_ssi_imx_probe(struct platform_device *pdev, - struct fsl_ssi_private *ssi_private, void __iomem *iomem) + struct fsl_ssi *ssi, void __iomem *iomem) { struct device_node *np = pdev->dev.of_node; u32 dmas[4]; int ret; - if (ssi_private->has_ipg_clk_name) - ssi_private->clk = devm_clk_get(&pdev->dev, "ipg"); + if (ssi->has_ipg_clk_name) + ssi->clk = devm_clk_get(&pdev->dev, "ipg"); else - ssi_private->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(ssi_private->clk)) { - ret = PTR_ERR(ssi_private->clk); + ssi->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(ssi->clk)) { + ret = PTR_ERR(ssi->clk); dev_err(&pdev->dev, "could not get clock: %d\n", ret); return ret; } - if (!ssi_private->has_ipg_clk_name) { - ret = clk_prepare_enable(ssi_private->clk); + if (!ssi->has_ipg_clk_name) { + ret = clk_prepare_enable(ssi->clk); if (ret) { dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret); return ret; @@ -1410,27 +1403,27 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, /* For those SLAVE implementations, we ignore non-baudclk cases * and, instead, abandon MASTER mode that needs baud clock. */ - ssi_private->baudclk = devm_clk_get(&pdev->dev, "baud"); - if (IS_ERR(ssi_private->baudclk)) + ssi->baudclk = devm_clk_get(&pdev->dev, "baud"); + if (IS_ERR(ssi->baudclk)) dev_dbg(&pdev->dev, "could not get baud clock: %ld\n", - PTR_ERR(ssi_private->baudclk)); + PTR_ERR(ssi->baudclk)); - ssi_private->dma_params_tx.maxburst = ssi_private->dma_maxburst; - ssi_private->dma_params_rx.maxburst = ssi_private->dma_maxburst; - ssi_private->dma_params_tx.addr = ssi_private->ssi_phys + CCSR_SSI_STX0; - ssi_private->dma_params_rx.addr = ssi_private->ssi_phys + CCSR_SSI_SRX0; + ssi->dma_params_tx.maxburst = ssi->dma_maxburst; + ssi->dma_params_rx.maxburst = ssi->dma_maxburst; + ssi->dma_params_tx.addr = ssi->ssi_phys + CCSR_SSI_STX0; + ssi->dma_params_rx.addr = ssi->ssi_phys + CCSR_SSI_SRX0; ret = of_property_read_u32_array(np, "dmas", dmas, 4); - if (ssi_private->use_dma && !ret && dmas[2] == IMX_DMATYPE_SSI_DUAL) { - ssi_private->use_dual_fifo = true; + if (ssi->use_dma && !ret && dmas[2] == IMX_DMATYPE_SSI_DUAL) { + ssi->use_dual_fifo = true; /* When using dual fifo mode, we need to keep watermark * as even numbers due to dma script limitation. */ - ssi_private->dma_params_tx.maxburst &= ~0x1; - ssi_private->dma_params_rx.maxburst &= ~0x1; + ssi->dma_params_tx.maxburst &= ~0x1; + ssi->dma_params_rx.maxburst &= ~0x1; } - if (!ssi_private->use_dma) { + if (!ssi->use_dma) { /* * Some boards use an incompatible codec. To get it @@ -1439,14 +1432,12 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, * situation. */ - ssi_private->fiq_params.irq = ssi_private->irq; - ssi_private->fiq_params.base = iomem; - ssi_private->fiq_params.dma_params_rx = - &ssi_private->dma_params_rx; - ssi_private->fiq_params.dma_params_tx = - &ssi_private->dma_params_tx; + ssi->fiq_params.irq = ssi->irq; + ssi->fiq_params.base = iomem; + ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx; + ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx; - ret = imx_pcm_fiq_init(pdev, &ssi_private->fiq_params); + ret = imx_pcm_fiq_init(pdev, &ssi->fiq_params); if (ret) goto error_pcm; } else { @@ -1459,23 +1450,23 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, error_pcm: - if (!ssi_private->has_ipg_clk_name) - clk_disable_unprepare(ssi_private->clk); + if (!ssi->has_ipg_clk_name) + clk_disable_unprepare(ssi->clk); return ret; } static void fsl_ssi_imx_clean(struct platform_device *pdev, - struct fsl_ssi_private *ssi_private) + struct fsl_ssi *ssi) { - if (!ssi_private->use_dma) + if (!ssi->use_dma) imx_pcm_fiq_exit(pdev); - if (!ssi_private->has_ipg_clk_name) - clk_disable_unprepare(ssi_private->clk); + if (!ssi->has_ipg_clk_name) + clk_disable_unprepare(ssi->clk); } static int fsl_ssi_probe(struct platform_device *pdev) { - struct fsl_ssi_private *ssi_private; + struct fsl_ssi *ssi; int ret = 0; struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id; @@ -1490,42 +1481,41 @@ static int fsl_ssi_probe(struct platform_device *pdev) if (!of_id || !of_id->data) return -EINVAL; - ssi_private = devm_kzalloc(&pdev->dev, sizeof(*ssi_private), + ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL); - if (!ssi_private) + if (!ssi) return -ENOMEM; - ssi_private->soc = of_id->data; - ssi_private->dev = &pdev->dev; + ssi->soc = of_id->data; + ssi->dev = &pdev->dev; sprop = of_get_property(np, "fsl,mode", NULL); if (sprop) { if (!strcmp(sprop, "ac97-slave")) - ssi_private->dai_fmt = SND_SOC_DAIFMT_AC97; + ssi->dai_fmt = SND_SOC_DAIFMT_AC97; } - ssi_private->use_dma = !of_property_read_bool(np, - "fsl,fiq-stream-filter"); + ssi->use_dma = !of_property_read_bool(np, "fsl,fiq-stream-filter"); - if (fsl_ssi_is_ac97(ssi_private)) { - memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_ac97_dai, + if (fsl_ssi_is_ac97(ssi)) { + memcpy(&ssi->cpu_dai_drv, &fsl_ssi_ac97_dai, sizeof(fsl_ssi_ac97_dai)); - fsl_ac97_data = ssi_private; + fsl_ac97_data = ssi; } else { /* Initialize this copy of the CPU DAI driver structure */ - memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template, + memcpy(&ssi->cpu_dai_drv, &fsl_ssi_dai_template, sizeof(fsl_ssi_dai_template)); } - ssi_private->cpu_dai_drv.name = dev_name(&pdev->dev); + ssi->cpu_dai_drv.name = dev_name(&pdev->dev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); iomem = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(iomem)) return PTR_ERR(iomem); - ssi_private->ssi_phys = res->start; + ssi->ssi_phys = res->start; - if (ssi_private->soc->imx21regs) { + if (ssi->soc->imx21regs) { /* * According to datasheet imx21-class SSI * don't have SACC{ST,EN,DIS} regs. @@ -1537,42 +1527,42 @@ static int fsl_ssi_probe(struct platform_device *pdev) ret = of_property_match_string(np, "clock-names", "ipg"); if (ret < 0) { - ssi_private->has_ipg_clk_name = false; - ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem, + ssi->has_ipg_clk_name = false; + ssi->regs = devm_regmap_init_mmio(&pdev->dev, iomem, ®config); } else { - ssi_private->has_ipg_clk_name = true; - ssi_private->regs = devm_regmap_init_mmio_clk(&pdev->dev, + ssi->has_ipg_clk_name = true; + ssi->regs = devm_regmap_init_mmio_clk(&pdev->dev, "ipg", iomem, ®config); } - if (IS_ERR(ssi_private->regs)) { + if (IS_ERR(ssi->regs)) { dev_err(&pdev->dev, "Failed to init register map\n"); - return PTR_ERR(ssi_private->regs); + return PTR_ERR(ssi->regs); } - ssi_private->irq = platform_get_irq(pdev, 0); - if (ssi_private->irq < 0) { + ssi->irq = platform_get_irq(pdev, 0); + if (ssi->irq < 0) { dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); - return ssi_private->irq; + return ssi->irq; } /* Are the RX and the TX clocks locked? */ if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) { - if (!fsl_ssi_is_ac97(ssi_private)) { - ssi_private->cpu_dai_drv.symmetric_rates = 1; - ssi_private->cpu_dai_drv.symmetric_samplebits = 1; + if (!fsl_ssi_is_ac97(ssi)) { + ssi->cpu_dai_drv.symmetric_rates = 1; + ssi->cpu_dai_drv.symmetric_samplebits = 1; } - ssi_private->cpu_dai_drv.symmetric_channels = 1; + ssi->cpu_dai_drv.symmetric_channels = 1; } /* Determine the FIFO depth. */ iprop = of_get_property(np, "fsl,fifo-depth", NULL); if (iprop) - ssi_private->fifo_depth = be32_to_cpup(iprop); + ssi->fifo_depth = be32_to_cpup(iprop); else /* Older 8610 DTs didn't have the fifo-depth property */ - ssi_private->fifo_depth = 8; + ssi->fifo_depth = 8; /* * Set the watermark for transmit FIFO 0 and receive FIFO 0. We don't @@ -1589,7 +1579,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) * fiq it is probably better to use the biggest possible watermark * size. */ - switch (ssi_private->fifo_depth) { + switch (ssi->fifo_depth) { case 15: /* * 2 samples is not enough when running at high data @@ -1598,8 +1588,8 @@ static int fsl_ssi_probe(struct platform_device *pdev) * for the DMA to fill the FIFO before it's over/under * run. */ - ssi_private->fifo_watermark = 8; - ssi_private->dma_maxburst = 8; + ssi->fifo_watermark = 8; + ssi->dma_maxburst = 8; break; case 8: default: @@ -1610,21 +1600,21 @@ static int fsl_ssi_probe(struct platform_device *pdev) * I suspect this could be changed to be something to * leave some more space in the fifo. */ - ssi_private->fifo_watermark = ssi_private->fifo_depth - 2; - ssi_private->dma_maxburst = ssi_private->fifo_depth - 2; + ssi->fifo_watermark = ssi->fifo_depth - 2; + ssi->dma_maxburst = ssi->fifo_depth - 2; break; } - dev_set_drvdata(&pdev->dev, ssi_private); + dev_set_drvdata(&pdev->dev, ssi); - if (ssi_private->soc->imx) { - ret = fsl_ssi_imx_probe(pdev, ssi_private, iomem); + if (ssi->soc->imx) { + ret = fsl_ssi_imx_probe(pdev, ssi, iomem); if (ret) return ret; } - if (fsl_ssi_is_ac97(ssi_private)) { - mutex_init(&ssi_private->ac97_reg_lock); + if (fsl_ssi_is_ac97(ssi)) { + mutex_init(&ssi->ac97_reg_lock); ret = snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev); if (ret) { dev_err(&pdev->dev, "could not set AC'97 ops\n"); @@ -1633,24 +1623,24 @@ static int fsl_ssi_probe(struct platform_device *pdev) } ret = devm_snd_soc_register_component(&pdev->dev, &fsl_ssi_component, - &ssi_private->cpu_dai_drv, 1); + &ssi->cpu_dai_drv, 1); if (ret) { dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); goto error_asoc_register; } - if (ssi_private->use_dma) { - ret = devm_request_irq(&pdev->dev, ssi_private->irq, + if (ssi->use_dma) { + ret = devm_request_irq(&pdev->dev, ssi->irq, fsl_ssi_isr, 0, dev_name(&pdev->dev), - ssi_private); + ssi); if (ret < 0) { dev_err(&pdev->dev, "could not claim irq %u\n", - ssi_private->irq); + ssi->irq); goto error_asoc_register; } } - ret = fsl_ssi_debugfs_create(&ssi_private->dbg_stats, &pdev->dev); + ret = fsl_ssi_debugfs_create(&ssi->dbg_stats, &pdev->dev); if (ret) goto error_asoc_register; @@ -1675,20 +1665,18 @@ static int fsl_ssi_probe(struct platform_device *pdev) snprintf(name, sizeof(name), "snd-soc-%s", sprop); make_lowercase(name); - ssi_private->pdev = - platform_device_register_data(&pdev->dev, name, 0, NULL, 0); - if (IS_ERR(ssi_private->pdev)) { - ret = PTR_ERR(ssi_private->pdev); + ssi->pdev = platform_device_register_data(&pdev->dev, name, 0, NULL, 0); + if (IS_ERR(ssi->pdev)) { + ret = PTR_ERR(ssi->pdev); dev_err(&pdev->dev, "failed to register platform: %d\n", ret); goto error_sound_card; } done: - if (ssi_private->dai_fmt) - _fsl_ssi_set_dai_fmt(&pdev->dev, ssi_private, - ssi_private->dai_fmt); + if (ssi->dai_fmt) + _fsl_ssi_set_dai_fmt(&pdev->dev, ssi, ssi->dai_fmt); - if (fsl_ssi_is_ac97(ssi_private)) { + if (fsl_ssi_is_ac97(ssi)) { u32 ssi_idx; ret = of_property_read_u32(np, "cell-index", &ssi_idx); @@ -1697,11 +1685,10 @@ done: goto error_sound_card; } - ssi_private->pdev = - platform_device_register_data(NULL, + ssi->pdev = platform_device_register_data(NULL, "ac97-codec", ssi_idx, NULL, 0); - if (IS_ERR(ssi_private->pdev)) { - ret = PTR_ERR(ssi_private->pdev); + if (IS_ERR(ssi->pdev)) { + ret = PTR_ERR(ssi->pdev); dev_err(&pdev->dev, "failed to register AC97 codec platform: %d\n", ret); @@ -1712,37 +1699,37 @@ done: return 0; error_sound_card: - fsl_ssi_debugfs_remove(&ssi_private->dbg_stats); + fsl_ssi_debugfs_remove(&ssi->dbg_stats); error_asoc_register: - if (fsl_ssi_is_ac97(ssi_private)) + if (fsl_ssi_is_ac97(ssi)) snd_soc_set_ac97_ops(NULL); error_ac97_ops: - if (fsl_ssi_is_ac97(ssi_private)) - mutex_destroy(&ssi_private->ac97_reg_lock); + if (fsl_ssi_is_ac97(ssi)) + mutex_destroy(&ssi->ac97_reg_lock); - if (ssi_private->soc->imx) - fsl_ssi_imx_clean(pdev, ssi_private); + if (ssi->soc->imx) + fsl_ssi_imx_clean(pdev, ssi); return ret; } static int fsl_ssi_remove(struct platform_device *pdev) { - struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev); + struct fsl_ssi *ssi = dev_get_drvdata(&pdev->dev); - fsl_ssi_debugfs_remove(&ssi_private->dbg_stats); + fsl_ssi_debugfs_remove(&ssi->dbg_stats); - if (ssi_private->pdev) - platform_device_unregister(ssi_private->pdev); + if (ssi->pdev) + platform_device_unregister(ssi->pdev); - if (ssi_private->soc->imx) - fsl_ssi_imx_clean(pdev, ssi_private); + if (ssi->soc->imx) + fsl_ssi_imx_clean(pdev, ssi); - if (fsl_ssi_is_ac97(ssi_private)) { + if (fsl_ssi_is_ac97(ssi)) { snd_soc_set_ac97_ops(NULL); - mutex_destroy(&ssi_private->ac97_reg_lock); + mutex_destroy(&ssi->ac97_reg_lock); } return 0; @@ -1751,13 +1738,11 @@ static int fsl_ssi_remove(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int fsl_ssi_suspend(struct device *dev) { - struct fsl_ssi_private *ssi_private = dev_get_drvdata(dev); - struct regmap *regs = ssi_private->regs; + struct fsl_ssi *ssi = dev_get_drvdata(dev); + struct regmap *regs = ssi->regs; - regmap_read(regs, CCSR_SSI_SFCSR, - &ssi_private->regcache_sfcsr); - regmap_read(regs, CCSR_SSI_SACNT, - &ssi_private->regcache_sacnt); + regmap_read(regs, CCSR_SSI_SFCSR, &ssi->regcache_sfcsr); + regmap_read(regs, CCSR_SSI_SACNT, &ssi->regcache_sacnt); regcache_cache_only(regs, true); regcache_mark_dirty(regs); @@ -1767,17 +1752,16 @@ static int fsl_ssi_suspend(struct device *dev) static int fsl_ssi_resume(struct device *dev) { - struct fsl_ssi_private *ssi_private = dev_get_drvdata(dev); - struct regmap *regs = ssi_private->regs; + struct fsl_ssi *ssi = dev_get_drvdata(dev); + struct regmap *regs = ssi->regs; regcache_cache_only(regs, false); regmap_update_bits(regs, CCSR_SSI_SFCSR, CCSR_SSI_SFCSR_RFWM1_MASK | CCSR_SSI_SFCSR_TFWM1_MASK | CCSR_SSI_SFCSR_RFWM0_MASK | CCSR_SSI_SFCSR_TFWM0_MASK, - ssi_private->regcache_sfcsr); - regmap_write(regs, CCSR_SSI_SACNT, - ssi_private->regcache_sacnt); + ssi->regcache_sfcsr); + regmap_write(regs, CCSR_SSI_SACNT, ssi->regcache_sacnt); return regcache_sync(regs); } -- cgit v1.2.3 From 8483c06797b62dbddac800b555b2fa1c689dbb1c Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sun, 17 Dec 2017 18:52:01 -0800 Subject: ASoC: fsl_ssi: Cache pdev->dev pointer There should be no trouble to understand dev = pdev->dev. This can save some space to have more print info or save some wrapped lines. Signed-off-by: Nicolin Chen Tested-by: Maciej S. Szmigiero Reviewed-by: Maciej S. Szmigiero Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 64 ++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 84d2f7ecb5e1..e903c92d5512 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1379,23 +1379,24 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, struct fsl_ssi *ssi, void __iomem *iomem) { struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; u32 dmas[4]; int ret; if (ssi->has_ipg_clk_name) - ssi->clk = devm_clk_get(&pdev->dev, "ipg"); + ssi->clk = devm_clk_get(dev, "ipg"); else - ssi->clk = devm_clk_get(&pdev->dev, NULL); + ssi->clk = devm_clk_get(dev, NULL); if (IS_ERR(ssi->clk)) { ret = PTR_ERR(ssi->clk); - dev_err(&pdev->dev, "could not get clock: %d\n", ret); + dev_err(dev, "could not get clock: %d\n", ret); return ret; } if (!ssi->has_ipg_clk_name) { ret = clk_prepare_enable(ssi->clk); if (ret) { - dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret); + dev_err(dev, "clk_prepare_enable failed: %d\n", ret); return ret; } } @@ -1403,9 +1404,9 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, /* For those SLAVE implementations, we ignore non-baudclk cases * and, instead, abandon MASTER mode that needs baud clock. */ - ssi->baudclk = devm_clk_get(&pdev->dev, "baud"); + ssi->baudclk = devm_clk_get(dev, "baud"); if (IS_ERR(ssi->baudclk)) - dev_dbg(&pdev->dev, "could not get baud clock: %ld\n", + dev_dbg(dev, "could not get baud clock: %ld\n", PTR_ERR(ssi->baudclk)); ssi->dma_params_tx.maxburst = ssi->dma_maxburst; @@ -1469,6 +1470,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) struct fsl_ssi *ssi; int ret = 0; struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; const struct of_device_id *of_id; const char *p, *sprop; const uint32_t *iprop; @@ -1477,17 +1479,16 @@ static int fsl_ssi_probe(struct platform_device *pdev) char name[64]; struct regmap_config regconfig = fsl_ssi_regconfig; - of_id = of_match_device(fsl_ssi_ids, &pdev->dev); + of_id = of_match_device(fsl_ssi_ids, dev); if (!of_id || !of_id->data) return -EINVAL; - ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), - GFP_KERNEL); + ssi = devm_kzalloc(dev, sizeof(*ssi), GFP_KERNEL); if (!ssi) return -ENOMEM; ssi->soc = of_id->data; - ssi->dev = &pdev->dev; + ssi->dev = dev; sprop = of_get_property(np, "fsl,mode", NULL); if (sprop) { @@ -1507,10 +1508,10 @@ static int fsl_ssi_probe(struct platform_device *pdev) memcpy(&ssi->cpu_dai_drv, &fsl_ssi_dai_template, sizeof(fsl_ssi_dai_template)); } - ssi->cpu_dai_drv.name = dev_name(&pdev->dev); + ssi->cpu_dai_drv.name = dev_name(dev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - iomem = devm_ioremap_resource(&pdev->dev, res); + iomem = devm_ioremap_resource(dev, res); if (IS_ERR(iomem)) return PTR_ERR(iomem); ssi->ssi_phys = res->start; @@ -1528,21 +1529,20 @@ static int fsl_ssi_probe(struct platform_device *pdev) ret = of_property_match_string(np, "clock-names", "ipg"); if (ret < 0) { ssi->has_ipg_clk_name = false; - ssi->regs = devm_regmap_init_mmio(&pdev->dev, iomem, - ®config); + ssi->regs = devm_regmap_init_mmio(dev, iomem, ®config); } else { ssi->has_ipg_clk_name = true; - ssi->regs = devm_regmap_init_mmio_clk(&pdev->dev, - "ipg", iomem, ®config); + ssi->regs = devm_regmap_init_mmio_clk(dev, "ipg", iomem, + ®config); } if (IS_ERR(ssi->regs)) { - dev_err(&pdev->dev, "Failed to init register map\n"); + dev_err(dev, "Failed to init register map\n"); return PTR_ERR(ssi->regs); } ssi->irq = platform_get_irq(pdev, 0); if (ssi->irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + dev_err(dev, "no irq for node %s\n", pdev->name); return ssi->irq; } @@ -1605,7 +1605,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) break; } - dev_set_drvdata(&pdev->dev, ssi); + dev_set_drvdata(dev, ssi); if (ssi->soc->imx) { ret = fsl_ssi_imx_probe(pdev, ssi, iomem); @@ -1617,30 +1617,28 @@ static int fsl_ssi_probe(struct platform_device *pdev) mutex_init(&ssi->ac97_reg_lock); ret = snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev); if (ret) { - dev_err(&pdev->dev, "could not set AC'97 ops\n"); + dev_err(dev, "could not set AC'97 ops\n"); goto error_ac97_ops; } } - ret = devm_snd_soc_register_component(&pdev->dev, &fsl_ssi_component, + ret = devm_snd_soc_register_component(dev, &fsl_ssi_component, &ssi->cpu_dai_drv, 1); if (ret) { - dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); + dev_err(dev, "failed to register DAI: %d\n", ret); goto error_asoc_register; } if (ssi->use_dma) { - ret = devm_request_irq(&pdev->dev, ssi->irq, - fsl_ssi_isr, 0, dev_name(&pdev->dev), - ssi); + ret = devm_request_irq(dev, ssi->irq, fsl_ssi_isr, 0, + dev_name(dev), ssi); if (ret < 0) { - dev_err(&pdev->dev, "could not claim irq %u\n", - ssi->irq); + dev_err(dev, "could not claim irq %u\n", ssi->irq); goto error_asoc_register; } } - ret = fsl_ssi_debugfs_create(&ssi->dbg_stats, &pdev->dev); + ret = fsl_ssi_debugfs_create(&ssi->dbg_stats, dev); if (ret) goto error_asoc_register; @@ -1665,23 +1663,23 @@ static int fsl_ssi_probe(struct platform_device *pdev) snprintf(name, sizeof(name), "snd-soc-%s", sprop); make_lowercase(name); - ssi->pdev = platform_device_register_data(&pdev->dev, name, 0, NULL, 0); + ssi->pdev = platform_device_register_data(dev, name, 0, NULL, 0); if (IS_ERR(ssi->pdev)) { ret = PTR_ERR(ssi->pdev); - dev_err(&pdev->dev, "failed to register platform: %d\n", ret); + dev_err(dev, "failed to register platform: %d\n", ret); goto error_sound_card; } done: if (ssi->dai_fmt) - _fsl_ssi_set_dai_fmt(&pdev->dev, ssi, ssi->dai_fmt); + _fsl_ssi_set_dai_fmt(dev, ssi, ssi->dai_fmt); if (fsl_ssi_is_ac97(ssi)) { u32 ssi_idx; ret = of_property_read_u32(np, "cell-index", &ssi_idx); if (ret) { - dev_err(&pdev->dev, "cannot get SSI index property\n"); + dev_err(dev, "cannot get SSI index property\n"); goto error_sound_card; } @@ -1689,7 +1687,7 @@ done: "ac97-codec", ssi_idx, NULL, 0); if (IS_ERR(ssi->pdev)) { ret = PTR_ERR(ssi->pdev); - dev_err(&pdev->dev, + dev_err(dev, "failed to register AC97 codec platform: %d\n", ret); goto error_sound_card; -- cgit v1.2.3 From 7a8fceb74de407f65201f3eaaee35377c2b71dbb Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sun, 17 Dec 2017 18:52:02 -0800 Subject: ASoC: fsl_ssi: Refine all comments This patch refines the comments by: 1) Removing all out-of-date comments 2) Removing all not-so-useful comments 3) Unifying the styles of all comments 4) Shortening comments to be more conise 5) Adding comments to improve code readablity 6) Moving all register related comments to fsl_ssi.h 7) Adding comments to all register and field defines Signed-off-by: Nicolin Chen Tested-by: Maciej S. Szmigiero Reviewed-by: Maciej S. Szmigiero Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 383 ++++++++++++++++---------------------------- sound/soc/fsl/fsl_ssi.h | 67 +++++++- sound/soc/fsl/fsl_ssi_dbg.c | 12 +- 3 files changed, 208 insertions(+), 254 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index e903c92d5512..ff1827a074be 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -187,42 +187,48 @@ struct fsl_ssi_soc_data { /** * fsl_ssi: per-SSI private data * - * @reg: Pointer to the regmap registers + * @regs: Pointer to the regmap registers * @irq: IRQ of this SSI * @cpu_dai_drv: CPU DAI driver for this device * * @dai_fmt: DAI configuration this device is currently used with - * @i2s_mode: i2s and network mode configuration of the device. Is used to - * switch between normal and i2s/network mode - * mode depending on the number of channels + * @i2s_mode: I2S and Network mode configuration of SCR register * @use_dma: DMA is used or FIQ with stream filter - * @use_dual_fifo: DMA with support for both FIFOs used - * @fifo_deph: Depth of the SSI FIFOs - * @slot_width: width of each DAI slot - * @slots: number of slots - * @rxtx_reg_val: Specific register settings for receive/transmit configuration + * @use_dual_fifo: DMA with support for dual FIFO mode + * @has_ipg_clk_name: If "ipg" is in the clock name list of device tree + * @fifo_depth: Depth of the SSI FIFOs + * @slot_width: Width of each DAI slot + * @slots: Number of slots + * @rxtx_reg_val: Specific RX/TX register settings * - * @clk: SSI clock - * @baudclk: SSI baud clock for master mode + * @clk: Clock source to access register + * @baudclk: Clock source to generate bit and frame-sync clocks * @baudclk_streams: Active streams that are using baudclk * + * @regcache_sfcsr: Cache sfcsr register value during suspend and resume + * @regcache_sacnt: Cache sacnt register value during suspend and resume + * * @dma_params_tx: DMA transmit parameters * @dma_params_rx: DMA receive parameters * @ssi_phys: physical address of the SSI registers * * @fiq_params: FIQ stream filtering parameters * - * @pdev: Pointer to pdev used for deprecated fsl-ssi sound card + * @pdev: Pointer to pdev when using fsl-ssi as sound card (ppc only) + * TODO: Should be replaced with simple-sound-card * * @dbg_stats: Debugging statistics * * @soc: SoC specific data + * @dev: Pointer to &pdev->dev + * + * @fifo_watermark: The FIFO watermark setting. Notifies DMA when there are + * @fifo_watermark or fewer words in TX fifo or + * @fifo_watermark or more empty words in RX fifo. + * @dma_maxburst: Max number of words to transfer in one go. So far, + * this is always the same as fifo_watermark. * - * @fifo_watermark: the FIFO watermark setting. Notifies DMA when - * there are @fifo_watermark or fewer words in TX fifo or - * @fifo_watermark or more empty words in RX fifo. - * @dma_maxburst: max number of words to transfer in one go. So far, - * this is always the same as fifo_watermark. + * @ac97_reg_lock: Mutex lock to serialize AC97 register access operations */ struct fsl_ssi { struct regmap *regs; @@ -243,20 +249,15 @@ struct fsl_ssi { struct clk *baudclk; unsigned int baudclk_streams; - /* regcache for volatile regs */ u32 regcache_sfcsr; u32 regcache_sacnt; - /* DMA params */ struct snd_dmaengine_dai_dma_data dma_params_tx; struct snd_dmaengine_dai_dma_data dma_params_rx; dma_addr_t ssi_phys; - /* params for non-dma FIQ stream filtered mode */ struct imx_pcm_fiq_params fiq_params; - /* Used when using fsl-ssi as sound-card. This is only used by ppc and - * should be replaced with simple-sound-card. */ struct platform_device *pdev; struct fsl_ssi_dbg dbg_stats; @@ -271,19 +272,19 @@ struct fsl_ssi { }; /* - * imx51 and later SoCs have a slightly different IP that allows the - * SSI configuration while the SSI unit is running. - * - * More important, it is necessary on those SoCs to configure the - * sperate TX/RX DMA bits just before starting the stream - * (fsl_ssi_trigger). The SDMA unit has to be configured before fsl_ssi - * sends any DMA requests to the SDMA unit, otherwise it is not defined - * how the SDMA unit handles the DMA request. + * SoC specific data * - * SDMA units are present on devices starting at imx35 but the imx35 - * reference manual states that the DMA bits should not be changed - * while the SSI unit is running (SSIEN). So we support the necessary - * online configuration of fsl-ssi starting at imx51. + * Notes: + * 1) SSI in earlier SoCS has critical bits in control registers that + * cannot be changed after SSI starts running -- a software reset + * (set SSIEN to 0) is required to change their values. So adding + * an offline_config flag for these SoCs. + * 2) SDMA is available since imx35. However, imx35 does not support + * DMA bits changing when SSI is running, so set offline_config. + * 3) imx51 and later versions support register configurations when + * SSI is running (SSIEN); For these versions, DMA needs to be + * configured before SSI sends DMA request to avoid an undefined + * DMA request on the SDMA side. */ static struct fsl_ssi_soc_data fsl_ssi_mpc8610 = { @@ -342,17 +343,9 @@ static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi *ssi) return (ssi->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFS; } + /** - * fsl_ssi_isr: SSI interrupt handler - * - * Although it's possible to use the interrupt handler to send and receive - * data to/from the SSI, we use the DMA instead. Programming is more - * complicated, but the performance is much better. - * - * This interrupt handler is used only to gather statistics. - * - * @irq: IRQ of the SSI device - * @dev_id: pointer to the fsl_ssi structure for this SSI device + * Interrupt handler to gather states */ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) { @@ -361,10 +354,6 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) __be32 sisr; __be32 sisr2; - /* We got an interrupt, so read the status register to see what we - were interrupted for. We mask it with the Interrupt Enable register - so that we only check for events that we're interested in. - */ regmap_read(regs, CCSR_SSI_SISR, &sisr); sisr2 = sisr & ssi->soc->sisr_write_mask; @@ -377,8 +366,8 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) return IRQ_HANDLED; } -/* - * Enable/Disable all rx/tx config flags at once. +/** + * Enable or disable all rx/tx config flags at once */ static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) { @@ -405,13 +394,8 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) } } -/* - * Clear RX or TX FIFO to remove samples from the previous - * stream session which may be still present in the FIFO and - * may introduce bad samples and/or channel slipping. - * - * Note: The SOR is not documented in recent IMX datasheet, but - * is described in IMX51 reference manual at section 56.3.3.15. +/** + * Clear remaining data in the FIFO to avoid dirty data or channel slipping */ static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) { @@ -424,7 +408,7 @@ static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) } } -/* +/** * Calculate the bits that have to be disabled for the current stream that is * getting disabled. This keeps the bits enabled that are necessary for the * second stream to work if 'stream_active' is true. @@ -444,9 +428,8 @@ static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) ((vals_disable) & \ ((vals_disable) ^ ((vals_stream) * (u32)!!(stream_active)))) -/* - * Enable/Disable a ssi configuration. You have to pass either - * ssi->rxtx_reg_val.rx or tx as vals parameter. +/** + * Enable or disable SSI configuration. */ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, struct fsl_ssi_reg_val *vals) @@ -467,24 +450,28 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, else keep_active = 0; - /* Find the other direction values rx or tx which we do not want to - * modify */ + /* Get the opposite direction to keep its values untouched */ if (&ssi->rxtx_reg_val.rx == vals) avals = &ssi->rxtx_reg_val.tx; else avals = &ssi->rxtx_reg_val.rx; - /* If vals should be disabled, start with disabling the unit */ if (!enable) { + /* + * To keep the other stream safe, exclude shared bits between + * both streams, and get safe bits to disable current stream + */ u32 scr = fsl_ssi_disable_val(vals->scr, avals->scr, keep_active); + /* Safely disable SCR register for the stream */ regmap_update_bits(regs, CCSR_SSI_SCR, scr, 0); } /* - * We are running on a SoC which does not support online SSI - * reconfiguration, so we have to enable all necessary flags at once - * even if we do not use them later (capture and playback configuration) + * For cases where online configuration is not supported, + * 1) Enable all necessary bits of both streams when 1st stream starts + * even if the opposite stream will not start + * 2) Disable all remaining bits of both streams when last stream ends */ if (ssi->soc->offline_config) { if ((enable && !nr_active_streams) || @@ -494,10 +481,7 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, goto config_done; } - /* - * Configure single direction units while the SSI unit is running - * (online configuration) - */ + /* Online configure single direction while SSI is running */ if (enable) { fsl_ssi_fifo_clear(ssi, vals->scr & CCSR_SSI_SCR_RE); @@ -510,15 +494,9 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, u32 stcr; /* - * Disabling the necessary flags for one of rx/tx while the - * other stream is active is a little bit more difficult. We - * have to disable only those flags that differ between both - * streams (rx XOR tx) and that are set in the stream that is - * disabled now. Otherwise we could alter flags of the other - * stream + * To keep the other stream safe, exclude shared bits between + * both streams, and get safe bits to disable current stream */ - - /* These assignments are simply vals without bits set in avals*/ sier = fsl_ssi_disable_val(vals->sier, avals->sier, keep_active); srcr = fsl_ssi_disable_val(vals->srcr, avals->srcr, @@ -526,6 +504,7 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, stcr = fsl_ssi_disable_val(vals->stcr, avals->stcr, keep_active); + /* Safely disable other control registers for the stream */ regmap_update_bits(regs, CCSR_SSI_SRCR, srcr, 0); regmap_update_bits(regs, CCSR_SSI_STCR, stcr, 0); regmap_update_bits(regs, CCSR_SSI_SIER, sier, 0); @@ -534,26 +513,21 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, config_done: /* Enabling of subunits is done after configuration */ if (enable) { + /* + * Start DMA before setting TE to avoid FIFO underrun + * which may cause a channel slip or a channel swap + * + * TODO: FIQ cases might also need this upon testing + */ if (ssi->use_dma && (vals->scr & CCSR_SSI_SCR_TE)) { - /* - * Be sure the Tx FIFO is filled when TE is set. - * Otherwise, there are some chances to start the - * playback with some void samples inserted first, - * generating a channel slip. - * - * First, SSIEN must be set, to let the FIFO be filled. - * - * Notes: - * - Limit this fix to the DMA case until FIQ cases can - * be tested. - * - Limit the length of the busy loop to not lock the - * system too long, even if 1-2 loops are sufficient - * in general. - */ int i; int max_loop = 100; + + /* Enable SSI first to send TX DMA request */ regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN, CCSR_SSI_SCR_SSIEN); + + /* Busy wait until TX FIFO not empty -- DMA working */ for (i = 0; i < max_loop; i++) { u32 sfcsr; regmap_read(regs, CCSR_SSI_SFCSR, &sfcsr); @@ -565,6 +539,7 @@ config_done: "Timeout waiting TX FIFO filling\n"); } } + /* Enable all remaining bits */ regmap_update_bits(regs, CCSR_SSI_SCR, vals->scr, vals->scr); } } @@ -581,20 +556,9 @@ static void fsl_ssi_tx_ac97_saccst_setup(struct fsl_ssi *ssi) /* no SACC{ST,EN,DIS} regs on imx21-class SSI */ if (!ssi->soc->imx21regs) { - /* - * Note that these below aren't just normal registers. - * They are a way to disable or enable bits in SACCST - * register: - * - writing a '1' bit at some position in SACCEN sets the - * relevant bit in SACCST, - * - writing a '1' bit at some position in SACCDIS unsets - * the relevant bit in SACCST register. - * - * The two writes below first disable all channels slots, - * then enable just slots 3 & 4 ("PCM Playback Left Channel" - * and "PCM Playback Right Channel"). - */ + /* Disable all channel slots */ regmap_write(regs, CCSR_SSI_SACCDIS, 0xff); + /* Enable slots 3 & 4 -- PCM Playback Left & Right channels */ regmap_write(regs, CCSR_SSI_SACCEN, 0x300); } } @@ -602,23 +566,11 @@ static void fsl_ssi_tx_ac97_saccst_setup(struct fsl_ssi *ssi) static void fsl_ssi_tx_config(struct fsl_ssi *ssi, bool enable) { /* - * Why are we setting up SACCST everytime we are starting a - * playback? - * Some CODECs (like VT1613 CODEC on UDOO board) like to - * (sometimes) set extra bits in their SLOTREQ requests. - * When a bit is set in a SLOTREQ request then SSI sets the - * relevant bit in SACCST automatically (it is enough if a bit was - * set in a SLOTREQ just once, bits in SACCST are 'sticky'). - * If an extra slot gets enabled that's a disaster for playback - * because some of normal left or right channel samples are - * redirected instead to this extra slot. + * SACCST might be modified via AC Link by a CODEC if it sends + * extra bits in their SLOTREQ requests, which'll accidentally + * send valid data to slots other than normal playback slots. * - * A workaround implemented in fsl-asoc-card of setting an - * appropriate CODEC register so that slots 3 & 4 (the normal - * stereo playback slots) are used for S/PDIF seems to mostly fix - * this issue on the UDOO board but since this CODEC is so - * untrustworthy let's play safe here and make sure that no extra - * slots are enabled every time a playback is started. + * To be safe, configure SACCST right before TX starts. */ if (enable && fsl_ssi_is_ac97(ssi)) fsl_ssi_tx_ac97_saccst_setup(ssi); @@ -626,10 +578,8 @@ static void fsl_ssi_tx_config(struct fsl_ssi *ssi, bool enable) fsl_ssi_config(ssi, enable, &ssi->rxtx_reg_val.tx); } -/* - * Setup rx/tx register values used to enable/disable the streams. These will - * be used later in fsl_ssi_config to setup the streams without the need to - * check for all different SSI modes. +/** + * Cache critical bits of SIER, SRCR, STCR and SCR to later set them safely */ static void fsl_ssi_setup_reg_vals(struct fsl_ssi *ssi) { @@ -642,6 +592,7 @@ static void fsl_ssi_setup_reg_vals(struct fsl_ssi *ssi) reg->tx.stcr = CCSR_SSI_STCR_TFEN0; reg->tx.scr = 0; + /* AC97 has already enabled SSIEN, RE and TE, so ignore them */ if (!fsl_ssi_is_ac97(ssi)) { reg->rx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE; reg->tx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE; @@ -663,24 +614,17 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi *ssi) { struct regmap *regs = ssi->regs; - /* - * Setup the clock control register - */ + /* Setup the clock control register */ regmap_write(regs, CCSR_SSI_STCCR, CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13)); regmap_write(regs, CCSR_SSI_SRCCR, CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13)); - /* - * Enable AC97 mode and startup the SSI - */ + /* Enable AC97 mode and startup the SSI */ regmap_write(regs, CCSR_SSI_SACNT, CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV); - /* - * Enable SSI, Transmit and Receive. AC97 has to communicate with the - * codec before a stream is started. - */ + /* AC97 has to communicate with codec before starting a stream */ regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE, CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE); @@ -688,14 +632,6 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi *ssi) regmap_write(regs, CCSR_SSI_SOR, CCSR_SSI_SOR_WAIT(3)); } -/** - * fsl_ssi_startup: create a new substream - * - * This is the first function called when a stream is opened. - * - * If this is the first stream open, then grab the IRQ and program most of - * the SSI registers. - */ static int fsl_ssi_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -707,7 +643,8 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, if (ret) return ret; - /* When using dual fifo mode, it is safer to ensure an even period + /* + * When using dual fifo mode, it is safer to ensure an even period * size. If appearing to an odd number while DMA always starts its * task from fifo0, fifo1 would be neglected at the end of each * period. But SSI would still access fifo1 with an invalid data. @@ -719,10 +656,6 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, return 0; } -/** - * fsl_ssi_shutdown: shutdown the SSI - * - */ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -734,7 +667,7 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, } /** - * fsl_ssi_set_bclk - configure Digital Audio Interface bit clock + * Configure Digital Audio Interface bit clock * * Note: This function can be only called when using SSI as DAI master * @@ -851,17 +784,15 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, } /** - * fsl_ssi_hw_params - program the sample size - * - * Most of the SSI registers have been programmed in the startup function, - * but the word length must be programmed here. Unfortunately, programming - * the SxCCR.WL bits requires the SSI to be temporarily disabled. This can - * cause a problem with supporting simultaneous playback and capture. If - * the SSI is already playing a stream, then that stream may be temporarily - * stopped when you start capture. + * Configure SSI based on PCM hardware parameters * - * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the - * clock master. + * Notes: + * 1) SxCCR.WL bits are critical bits that require SSI to be temporarily + * disabled on offline_config SoCs. Even for online configurable SoCs + * running in synchronous mode (both TX and RX use STCCR), it is not + * safe to re-configure them when both two streams start running. + * 2) SxCCR.PM, SxCCR.DIV2 and SxCCR.PSR bits will be configured in the + * fsl_ssi_set_bclk() if SSI is the DAI clock master. */ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai) @@ -879,8 +810,10 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, enabled = scr_val & CCSR_SSI_SCR_SSIEN; /* - * If we're in synchronous mode, and the SSI is already enabled, - * then STCCR is already set properly. + * SSI is properly configured if it is enabled and running in + * the synchronous mode; Note that AC97 mode is an exception + * that should set separate configurations for STCCR and SRCCR + * despite running in the synchronous mode. */ if (enabled && ssi->cpu_dai_drv.symmetric_rates) return 0; @@ -902,10 +835,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, if (!fsl_ssi_is_ac97(ssi)) { u8 i2smode; - /* - * Switch to normal net mode in order to have a frame sync - * signal every 32 bits instead of 16 bits - */ + /* Normal + Network mode to send 16-bit data in 32-bit frames */ if (fsl_ssi_is_i2s_cbm_cfs(ssi) && sample_size == 16) i2smode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET; @@ -917,16 +847,6 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, channels == 1 ? 0 : i2smode); } - /* - * FIXME: The documentation says that SxCCR[WL] should not be - * modified while the SSI is enabled. The only time this can - * happen is if we're trying to do simultaneous playback and - * capture in asynchronous mode. Unfortunately, I have been enable - * to get that to work at all on the P1022DS. Therefore, we don't - * bother to disable/enable the SSI when setting SxCCR[WL], because - * the SSI will stop anyway. Maybe one day, this will get fixed. - */ - /* In synchronous mode, the SSI uses STCCR for capture */ if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) || ssi->cpu_dai_drv.symmetric_rates) @@ -972,6 +892,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, regmap_read(regs, CCSR_SSI_SCR, &scr); scr &= ~(CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_I2S_MODE_MASK); + /* Synchronize frame sync clock for TE to avoid data slipping */ scr |= CCSR_SSI_SCR_SYNC_TX_FS; mask = CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR | @@ -982,6 +903,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, stcr &= ~mask; srcr &= ~mask; + /* Use Network mode as default */ ssi->i2s_mode = CCSR_SSI_SCR_NET; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -1022,6 +944,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, CCSR_SSI_STCR_TXBIT0; break; case SND_SOC_DAIFMT_AC97: + /* Data on falling edge of bclk, frame high, 1clk before data */ ssi->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_NORMAL; break; default: @@ -1054,13 +977,16 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, /* DAI clock master masks */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: + /* Output bit and frame sync clocks */ strcr |= CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR; scr |= CCSR_SSI_SCR_SYS_CLK_EN; break; case SND_SOC_DAIFMT_CBM_CFM: + /* Input bit or frame sync clocks */ scr &= ~CCSR_SSI_SCR_SYS_CLK_EN; break; case SND_SOC_DAIFMT_CBM_CFS: + /* Input bit clock but output frame sync clock */ strcr &= ~CCSR_SSI_STCR_TXDIR; strcr |= CCSR_SSI_STCR_TFDIR; scr &= ~CCSR_SSI_SCR_SYS_CLK_EN; @@ -1073,8 +999,8 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, stcr |= strcr; srcr |= strcr; + /* Set SYN mode and clear RXDIR bit when using SYN or AC97 mode */ if (ssi->cpu_dai_drv.symmetric_rates || fsl_ssi_is_ac97(ssi)) { - /* Need to clear RXDIR when using SYNC or AC97 mode */ srcr &= ~CCSR_SSI_SRCR_RXDIR; scr |= CCSR_SSI_SCR_SYN; } @@ -1106,12 +1032,13 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, } /** - * fsl_ssi_set_dai_fmt - configure Digital Audio Interface Format. + * Configure Digital Audio Interface (DAI) Format */ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + /* AC97 configured DAIFMT earlier in the probe() */ if (fsl_ssi_is_ac97(ssi)) return 0; @@ -1119,9 +1046,7 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) } /** - * fsl_ssi_set_dai_tdm_slot - set TDM slot number - * - * Note: This function can be only called when using SSI as DAI master + * Set TDM slot number and slot width */ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, u32 rx_mask, int slots, int slot_width) @@ -1149,17 +1074,17 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, regmap_update_bits(regs, CCSR_SSI_SRCCR, CCSR_SSI_SxCCR_DC_MASK, CCSR_SSI_SxCCR_DC(slots)); - /* The register SxMSKs needs SSI to provide essential clock due to - * hardware design. So we here temporarily enable SSI to set them. - */ + /* Save SSIEN bit of the SCR register */ regmap_read(regs, CCSR_SSI_SCR, &val); val &= CCSR_SSI_SCR_SSIEN; + /* Temporarily enable SSI to allow SxMSKs to be configurable */ regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN, CCSR_SSI_SCR_SSIEN); regmap_write(regs, CCSR_SSI_STMSK, ~tx_mask); regmap_write(regs, CCSR_SSI_SRMSK, ~rx_mask); + /* Restore the value of SSIEN bit */ regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN, val); ssi->slot_width = slot_width; @@ -1169,10 +1094,7 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, } /** - * fsl_ssi_trigger: start and stop the DMA transfer. - * - * This function is called by ALSA to start, stop, pause, and resume the DMA - * transfer of data. + * Start or stop SSI and corresponding DMA transaction. * * The DMA channel is in external master start and pause mode, which * means the SSI completely controls the flow of data. @@ -1207,6 +1129,7 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, return -EINVAL; } + /* Clear corresponding FIFO */ if (fsl_ssi_is_ac97(ssi)) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) regmap_write(regs, CCSR_SSI_SOR, CCSR_SSI_SOR_TX_CLR); @@ -1239,7 +1162,6 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { .trigger = fsl_ssi_trigger, }; -/* Template for the CPU dai driver structure */ static struct snd_soc_dai_driver fsl_ssi_dai_template = { .probe = fsl_ssi_dai_probe, .playback = { @@ -1383,6 +1305,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, u32 dmas[4]; int ret; + /* Backward compatible for a DT without ipg clock name assigned */ if (ssi->has_ipg_clk_name) ssi->clk = devm_clk_get(dev, "ipg"); else @@ -1393,6 +1316,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, return ret; } + /* Enable the clock since regmap will not handle it in this case */ if (!ssi->has_ipg_clk_name) { ret = clk_prepare_enable(ssi->clk); if (ret) { @@ -1401,9 +1325,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, } } - /* For those SLAVE implementations, we ignore non-baudclk cases - * and, instead, abandon MASTER mode that needs baud clock. - */ + /* Do not error out for slave cases that live without a baud clock */ ssi->baudclk = devm_clk_get(dev, "baud"); if (IS_ERR(ssi->baudclk)) dev_dbg(dev, "could not get baud clock: %ld\n", @@ -1414,25 +1336,23 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, ssi->dma_params_tx.addr = ssi->ssi_phys + CCSR_SSI_STX0; ssi->dma_params_rx.addr = ssi->ssi_phys + CCSR_SSI_SRX0; + /* Set to dual FIFO mode according to the SDMA sciprt */ ret = of_property_read_u32_array(np, "dmas", dmas, 4); if (ssi->use_dma && !ret && dmas[2] == IMX_DMATYPE_SSI_DUAL) { ssi->use_dual_fifo = true; - /* When using dual fifo mode, we need to keep watermark - * as even numbers due to dma script limitation. + /* + * Use even numbers to avoid channel swap due to SDMA + * script design */ ssi->dma_params_tx.maxburst &= ~0x1; ssi->dma_params_rx.maxburst &= ~0x1; } if (!ssi->use_dma) { - /* - * Some boards use an incompatible codec. To get it - * working, we are using imx-fiq-pcm-audio, that - * can handle those codecs. DMA is not possible in this - * situation. + * Some boards use an incompatible codec. Use imx-fiq-pcm-audio + * to get it working, as DMA is not possible in this situation. */ - ssi->fiq_params.irq = ssi->irq; ssi->fiq_params.base = iomem; ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx; @@ -1490,12 +1410,14 @@ static int fsl_ssi_probe(struct platform_device *pdev) ssi->soc = of_id->data; ssi->dev = dev; + /* Check if being used in AC97 mode */ sprop = of_get_property(np, "fsl,mode", NULL); if (sprop) { if (!strcmp(sprop, "ac97-slave")) ssi->dai_fmt = SND_SOC_DAIFMT_AC97; } + /* Select DMA or FIQ */ ssi->use_dma = !of_property_read_bool(np, "fsl,fiq-stream-filter"); if (fsl_ssi_is_ac97(ssi)) { @@ -1504,7 +1426,6 @@ static int fsl_ssi_probe(struct platform_device *pdev) fsl_ac97_data = ssi; } else { - /* Initialize this copy of the CPU DAI driver structure */ memcpy(&ssi->cpu_dai_drv, &fsl_ssi_dai_template, sizeof(fsl_ssi_dai_template)); } @@ -1517,10 +1438,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) ssi->ssi_phys = res->start; if (ssi->soc->imx21regs) { - /* - * According to datasheet imx21-class SSI - * don't have SACC{ST,EN,DIS} regs. - */ + /* No SACC{ST,EN,DIS} regs in imx21-class SSI */ regconfig.max_register = CCSR_SSI_SRMSK; regconfig.num_reg_defaults_raw = CCSR_SSI_SRMSK / sizeof(uint32_t) + 1; @@ -1546,7 +1464,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) return ssi->irq; } - /* Are the RX and the TX clocks locked? */ + /* Set software limitations for synchronous mode */ if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) { if (!fsl_ssi_is_ac97(ssi)) { ssi->cpu_dai_drv.symmetric_rates = 1; @@ -1556,50 +1474,35 @@ static int fsl_ssi_probe(struct platform_device *pdev) ssi->cpu_dai_drv.symmetric_channels = 1; } - /* Determine the FIFO depth. */ + /* Fetch FIFO depth; Set to 8 for older DT without this property */ iprop = of_get_property(np, "fsl,fifo-depth", NULL); if (iprop) ssi->fifo_depth = be32_to_cpup(iprop); else - /* Older 8610 DTs didn't have the fifo-depth property */ ssi->fifo_depth = 8; /* - * Set the watermark for transmit FIFO 0 and receive FIFO 0. We don't - * use FIFO 1 but set the watermark appropriately nontheless. - * We program the transmit water to signal a DMA transfer - * if there are N elements left in the FIFO. For chips with 15-deep - * FIFOs, set watermark to 8. This allows the SSI to operate at a - * high data rate without channel slipping. Behavior is unchanged - * for the older chips with a fifo depth of only 8. A value of 4 - * might be appropriate for the older chips, but is left at - * fifo_depth-2 until sombody has a chance to test. + * Configure TX and RX DMA watermarks -- when to send a DMA request * - * We set the watermark on the same level as the DMA burstsize. For - * fiq it is probably better to use the biggest possible watermark - * size. + * Values should be tested to avoid FIFO under/over run. Set maxburst + * to fifo_watermark to maxiumize DMA transaction to reduce overhead. */ switch (ssi->fifo_depth) { case 15: /* - * 2 samples is not enough when running at high data - * rates (like 48kHz @ 16 bits/channel, 16 channels) - * 8 seems to split things evenly and leave enough time - * for the DMA to fill the FIFO before it's over/under - * run. + * Set to 8 as a balanced configuration -- When TX FIFO has 8 + * empty slots, send a DMA request to fill these 8 slots. The + * remaining 7 slots should be able to allow DMA to finish the + * transaction before TX FIFO underruns; Same applies to RX. + * + * Tested with cases running at 48kHz @ 16 bits x 16 channels */ ssi->fifo_watermark = 8; ssi->dma_maxburst = 8; break; case 8: default: - /* - * maintain old behavior for older chips. - * Keeping it the same because I don't have an older - * board to test with. - * I suspect this could be changed to be something to - * leave some more space in the fifo. - */ + /* Safely use old watermark configurations for older chips */ ssi->fifo_watermark = ssi->fifo_depth - 2; ssi->dma_maxburst = ssi->fifo_depth - 2; break; @@ -1642,18 +1545,14 @@ static int fsl_ssi_probe(struct platform_device *pdev) if (ret) goto error_asoc_register; - /* - * If codec-handle property is missing from SSI node, we assume - * that the machine driver uses new binding which does not require - * SSI driver to trigger machine driver's probe. - */ + /* Bypass it if using newer DT bindings of ASoC machine drivers */ if (!of_get_property(np, "codec-handle", NULL)) goto done; - /* Trigger the machine driver's probe function. The platform driver - * name of the machine driver is taken from /compatible property of the - * device tree. We also pass the address of the CPU DAI driver - * structure. + /* + * Backward compatible for older bindings by manually triggering the + * machine driver's probe(). Use /compatible property, including the + * address of CPU DAI driver structure, as the name of machine driver. */ sprop = of_get_property(of_find_node_by_path("/"), "compatible", NULL); /* Sometimes the compatible name has a "fsl," prefix, so we strip it. */ diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h index 506510540d0a..1ad3bde7f065 100644 --- a/sound/soc/fsl/fsl_ssi.h +++ b/sound/soc/fsl/fsl_ssi.h @@ -1,5 +1,5 @@ /* - * fsl_ssi.h - ALSA SSI interface for the Freescale MPC8610 SoC + * fsl_ssi.h - ALSA SSI interface for the Freescale MPC8610 and i.MX SoC * * Author: Timur Tabi * @@ -12,31 +12,75 @@ #ifndef _MPC8610_I2S_H #define _MPC8610_I2S_H -/* SSI registers */ +/* -- SSI Register Map -- */ + +/* SSI Transmit Data Register 0 */ #define CCSR_SSI_STX0 0x00 +/* SSI Transmit Data Register 1 */ #define CCSR_SSI_STX1 0x04 +/* SSI Receive Data Register 0 */ #define CCSR_SSI_SRX0 0x08 +/* SSI Receive Data Register 1 */ #define CCSR_SSI_SRX1 0x0c +/* SSI Control Register */ #define CCSR_SSI_SCR 0x10 +/* SSI Interrupt Status Register */ #define CCSR_SSI_SISR 0x14 +/* SSI Interrupt Enable Register */ #define CCSR_SSI_SIER 0x18 +/* SSI Transmit Configuration Register */ #define CCSR_SSI_STCR 0x1c +/* SSI Receive Configuration Register */ #define CCSR_SSI_SRCR 0x20 +/* SSI Transmit Clock Control Register */ #define CCSR_SSI_STCCR 0x24 +/* SSI Receive Clock Control Register */ #define CCSR_SSI_SRCCR 0x28 +/* SSI FIFO Control/Status Register */ #define CCSR_SSI_SFCSR 0x2c +/* + * SSI Test Register (Intended for debugging purposes only) + * + * Note: STR is not documented in recent IMX datasheet, but + * is described in IMX51 reference manual at section 56.3.3.14 + */ #define CCSR_SSI_STR 0x30 +/* + * SSI Option Register (Intended for internal use only) + * + * Note: SOR is not documented in recent IMX datasheet, but + * is described in IMX51 reference manual at section 56.3.3.15 + */ #define CCSR_SSI_SOR 0x34 +/* SSI AC97 Control Register */ #define CCSR_SSI_SACNT 0x38 +/* SSI AC97 Command Address Register */ #define CCSR_SSI_SACADD 0x3c +/* SSI AC97 Command Data Register */ #define CCSR_SSI_SACDAT 0x40 +/* SSI AC97 Tag Register */ #define CCSR_SSI_SATAG 0x44 +/* SSI Transmit Time Slot Mask Register */ #define CCSR_SSI_STMSK 0x48 +/* SSI Receive Time Slot Mask Register */ #define CCSR_SSI_SRMSK 0x4c +/* + * SSI AC97 Channel Status Register + * + * The status could be changed by: + * 1) Writing a '1' bit at some position in SACCEN sets relevant bit in SACCST + * 2) Writing a '1' bit at some position in SACCDIS unsets the relevant bit + * 3) Receivng a '1' in SLOTREQ bit from external CODEC via AC Link + */ #define CCSR_SSI_SACCST 0x50 +/* SSI AC97 Channel Enable Register -- Set bits in SACCST */ #define CCSR_SSI_SACCEN 0x54 +/* SSI AC97 Channel Disable Register -- Clear bits in SACCST */ #define CCSR_SSI_SACCDIS 0x58 +/* -- SSI Register Field Maps -- */ + +/* SSI Control Register -- CCSR_SSI_SCR 0x10 */ #define CCSR_SSI_SCR_SYNC_TX_FS 0x00001000 #define CCSR_SSI_SCR_RFR_CLK_DIS 0x00000800 #define CCSR_SSI_SCR_TFR_CLK_DIS 0x00000400 @@ -52,6 +96,7 @@ #define CCSR_SSI_SCR_TE 0x00000002 #define CCSR_SSI_SCR_SSIEN 0x00000001 +/* SSI Interrupt Status Register -- CCSR_SSI_SISR 0x14 */ #define CCSR_SSI_SISR_RFRC 0x01000000 #define CCSR_SSI_SISR_TFRC 0x00800000 #define CCSR_SSI_SISR_CMDAU 0x00040000 @@ -74,6 +119,7 @@ #define CCSR_SSI_SISR_TFE1 0x00000002 #define CCSR_SSI_SISR_TFE0 0x00000001 +/* SSI Interrupt Enable Register -- CCSR_SSI_SIER 0x18 */ #define CCSR_SSI_SIER_RFRC_EN 0x01000000 #define CCSR_SSI_SIER_TFRC_EN 0x00800000 #define CCSR_SSI_SIER_RDMAE 0x00400000 @@ -100,6 +146,7 @@ #define CCSR_SSI_SIER_TFE1_EN 0x00000002 #define CCSR_SSI_SIER_TFE0_EN 0x00000001 +/* SSI Transmit Configuration Register -- CCSR_SSI_STCR 0x1C */ #define CCSR_SSI_STCR_TXBIT0 0x00000200 #define CCSR_SSI_STCR_TFEN1 0x00000100 #define CCSR_SSI_STCR_TFEN0 0x00000080 @@ -111,6 +158,7 @@ #define CCSR_SSI_STCR_TFSL 0x00000002 #define CCSR_SSI_STCR_TEFS 0x00000001 +/* SSI Receive Configuration Register -- CCSR_SSI_SRCR 0x20 */ #define CCSR_SSI_SRCR_RXEXT 0x00000400 #define CCSR_SSI_SRCR_RXBIT0 0x00000200 #define CCSR_SSI_SRCR_RFEN1 0x00000100 @@ -123,7 +171,10 @@ #define CCSR_SSI_SRCR_RFSL 0x00000002 #define CCSR_SSI_SRCR_REFS 0x00000001 -/* STCCR and SRCCR */ +/* + * SSI Transmit Clock Control Register -- CCSR_SSI_STCCR 0x24 + * SSI Receive Clock Control Register -- CCSR_SSI_SRCCR 0x28 + */ #define CCSR_SSI_SxCCR_DIV2_SHIFT 18 #define CCSR_SSI_SxCCR_DIV2 0x00040000 #define CCSR_SSI_SxCCR_PSR_SHIFT 17 @@ -142,9 +193,10 @@ ((((x) - 1) << CCSR_SSI_SxCCR_PM_SHIFT) & CCSR_SSI_SxCCR_PM_MASK) /* - * The xFCNT bits are read-only, and the xFWM bits are read/write. Use the - * CCSR_SSI_SFCSR_xFCNTy() macros to read the FIFO counters, and use the - * CCSR_SSI_SFCSR_xFWMy() macros to set the watermarks. + * SSI FIFO Control/Status Register -- CCSR_SSI_SFCSR 0x2c + * + * Tx or Rx FIFO Counter -- CCSR_SSI_SFCSR_xFCNTy Read-Only + * Tx or Rx FIFO Watermarks -- CCSR_SSI_SFCSR_xFWMy Read/Write */ #define CCSR_SSI_SFCSR_RFCNT1_SHIFT 28 #define CCSR_SSI_SFCSR_RFCNT1_MASK 0xF0000000 @@ -179,6 +231,7 @@ #define CCSR_SSI_SFCSR_TFWM0(x) \ (((x) << CCSR_SSI_SFCSR_TFWM0_SHIFT) & CCSR_SSI_SFCSR_TFWM0_MASK) +/* SSI Test Register -- CCSR_SSI_STR 0x30 */ #define CCSR_SSI_STR_TEST 0x00008000 #define CCSR_SSI_STR_RCK2TCK 0x00004000 #define CCSR_SSI_STR_RFS2TFS 0x00002000 @@ -188,6 +241,7 @@ #define CCSR_SSI_STR_TFS2RFS 0x00000020 #define CCSR_SSI_STR_TXSTATE(x) ((x) & 0x1F) +/* SSI Option Register -- CCSR_SSI_SOR 0x34 */ #define CCSR_SSI_SOR_CLKOFF 0x00000040 #define CCSR_SSI_SOR_RX_CLR 0x00000020 #define CCSR_SSI_SOR_TX_CLR 0x00000010 @@ -197,6 +251,7 @@ #define CCSR_SSI_SOR_WAIT(x) (((x) & 3) << CCSR_SSI_SOR_WAIT_SHIFT) #define CCSR_SSI_SOR_SYNRST 0x00000001 +/* SSI AC97 Control Register -- CCSR_SSI_SACNT 0x38 */ #define CCSR_SSI_SACNT_FRDIV(x) (((x) & 0x3f) << 5) #define CCSR_SSI_SACNT_WR 0x00000010 #define CCSR_SSI_SACNT_RD 0x00000008 diff --git a/sound/soc/fsl/fsl_ssi_dbg.c b/sound/soc/fsl/fsl_ssi_dbg.c index 5469ffbc0253..88d9e8e08905 100644 --- a/sound/soc/fsl/fsl_ssi_dbg.c +++ b/sound/soc/fsl/fsl_ssi_dbg.c @@ -82,9 +82,10 @@ void fsl_ssi_dbg_isr(struct fsl_ssi_dbg *dbg, u32 sisr) dbg->stats.tfe0++; } -/* Show the statistics of a flag only if its interrupt is enabled. The - * compiler will optimze this code to a no-op if the interrupt is not - * enabled. +/** + * Show the statistics of a flag only if its interrupt is enabled + * + * Compilers will optimize it to a no-op if the interrupt is disabled */ #define SIER_SHOW(flag, name) \ do { \ @@ -94,10 +95,9 @@ void fsl_ssi_dbg_isr(struct fsl_ssi_dbg *dbg, u32 sisr) /** - * fsl_sysfs_ssi_show: display SSI statistics + * Display the statistics for the current SSI device * - * Display the statistics for the current SSI device. To avoid confusion, - * we only show those counts that are enabled. + * To avoid confusion, only show those counts that are enabled */ static int fsl_ssi_stats_show(struct seq_file *s, void *unused) { -- cgit v1.2.3 From a818aa5f967ba60522ee0ad181a0c5a96b65d999 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sun, 17 Dec 2017 18:52:03 -0800 Subject: ASoC: fsl_ssi: Rename registers and fields macros This patch renames CCSR_SSI_xxx to REG_SSI_xxx and SSI_xxx_yyy style. It also slightly reduces the length of them to save some space. Signed-off-by: Nicolin Chen Tested-by: Maciej S. Szmigiero Reviewed-by: Maciej S. Szmigiero Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 374 +++++++++++++++++++++---------------------- sound/soc/fsl/fsl_ssi.h | 376 ++++++++++++++++++++++---------------------- sound/soc/fsl/fsl_ssi_dbg.c | 44 +++--- 3 files changed, 397 insertions(+), 397 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index ff1827a074be..24d96956b53a 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -78,12 +78,12 @@ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) #endif -#define FSLSSI_SIER_DBG_RX_FLAGS (CCSR_SSI_SIER_RFF0_EN | \ - CCSR_SSI_SIER_RLS_EN | CCSR_SSI_SIER_RFS_EN | \ - CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_RFRC_EN) -#define FSLSSI_SIER_DBG_TX_FLAGS (CCSR_SSI_SIER_TFE0_EN | \ - CCSR_SSI_SIER_TLS_EN | CCSR_SSI_SIER_TFS_EN | \ - CCSR_SSI_SIER_TUE0_EN | CCSR_SSI_SIER_TFRC_EN) +#define FSLSSI_SIER_DBG_RX_FLAGS (SSI_SIER_RFF0_EN | \ + SSI_SIER_RLS_EN | SSI_SIER_RFS_EN | \ + SSI_SIER_ROE0_EN | SSI_SIER_RFRC_EN) +#define FSLSSI_SIER_DBG_TX_FLAGS (SSI_SIER_TFE0_EN | \ + SSI_SIER_TLS_EN | SSI_SIER_TFS_EN | \ + SSI_SIER_TUE0_EN | SSI_SIER_TFRC_EN) enum fsl_ssi_type { FSL_SSI_MCP8610, @@ -107,8 +107,8 @@ struct fsl_ssi_rxtx_reg_val { static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { - case CCSR_SSI_SACCEN: - case CCSR_SSI_SACCDIS: + case REG_SSI_SACCEN: + case REG_SSI_SACCDIS: return false; default: return true; @@ -118,18 +118,18 @@ static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg) static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { - case CCSR_SSI_STX0: - case CCSR_SSI_STX1: - case CCSR_SSI_SRX0: - case CCSR_SSI_SRX1: - case CCSR_SSI_SISR: - case CCSR_SSI_SFCSR: - case CCSR_SSI_SACNT: - case CCSR_SSI_SACADD: - case CCSR_SSI_SACDAT: - case CCSR_SSI_SATAG: - case CCSR_SSI_SACCST: - case CCSR_SSI_SOR: + case REG_SSI_STX0: + case REG_SSI_STX1: + case REG_SSI_SRX0: + case REG_SSI_SRX1: + case REG_SSI_SISR: + case REG_SSI_SFCSR: + case REG_SSI_SACNT: + case REG_SSI_SACADD: + case REG_SSI_SACDAT: + case REG_SSI_SATAG: + case REG_SSI_SACCST: + case REG_SSI_SOR: return true; default: return false; @@ -139,12 +139,12 @@ static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg) static bool fsl_ssi_precious_reg(struct device *dev, unsigned int reg) { switch (reg) { - case CCSR_SSI_SRX0: - case CCSR_SSI_SRX1: - case CCSR_SSI_SISR: - case CCSR_SSI_SACADD: - case CCSR_SSI_SACDAT: - case CCSR_SSI_SATAG: + case REG_SSI_SRX0: + case REG_SSI_SRX1: + case REG_SSI_SISR: + case REG_SSI_SACADD: + case REG_SSI_SACDAT: + case REG_SSI_SATAG: return true; default: return false; @@ -154,9 +154,9 @@ static bool fsl_ssi_precious_reg(struct device *dev, unsigned int reg) static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { - case CCSR_SSI_SRX0: - case CCSR_SSI_SRX1: - case CCSR_SSI_SACCST: + case REG_SSI_SRX0: + case REG_SSI_SRX1: + case REG_SSI_SACCST: return false; default: return true; @@ -164,12 +164,12 @@ static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg) } static const struct regmap_config fsl_ssi_regconfig = { - .max_register = CCSR_SSI_SACCDIS, + .max_register = REG_SSI_SACCDIS, .reg_bits = 32, .val_bits = 32, .reg_stride = 4, .val_format_endian = REGMAP_ENDIAN_NATIVE, - .num_reg_defaults_raw = CCSR_SSI_SACCDIS / sizeof(uint32_t) + 1, + .num_reg_defaults_raw = REG_SSI_SACCDIS / sizeof(uint32_t) + 1, .readable_reg = fsl_ssi_readable_reg, .volatile_reg = fsl_ssi_volatile_reg, .precious_reg = fsl_ssi_precious_reg, @@ -290,9 +290,9 @@ struct fsl_ssi { static struct fsl_ssi_soc_data fsl_ssi_mpc8610 = { .imx = false, .offline_config = true, - .sisr_write_mask = CCSR_SSI_SISR_RFRC | CCSR_SSI_SISR_TFRC | - CCSR_SSI_SISR_ROE0 | CCSR_SSI_SISR_ROE1 | - CCSR_SSI_SISR_TUE0 | CCSR_SSI_SISR_TUE1, + .sisr_write_mask = SSI_SISR_RFRC | SSI_SISR_TFRC | + SSI_SISR_ROE0 | SSI_SISR_ROE1 | + SSI_SISR_TUE0 | SSI_SISR_TUE1, }; static struct fsl_ssi_soc_data fsl_ssi_imx21 = { @@ -305,16 +305,16 @@ static struct fsl_ssi_soc_data fsl_ssi_imx21 = { static struct fsl_ssi_soc_data fsl_ssi_imx35 = { .imx = true, .offline_config = true, - .sisr_write_mask = CCSR_SSI_SISR_RFRC | CCSR_SSI_SISR_TFRC | - CCSR_SSI_SISR_ROE0 | CCSR_SSI_SISR_ROE1 | - CCSR_SSI_SISR_TUE0 | CCSR_SSI_SISR_TUE1, + .sisr_write_mask = SSI_SISR_RFRC | SSI_SISR_TFRC | + SSI_SISR_ROE0 | SSI_SISR_ROE1 | + SSI_SISR_TUE0 | SSI_SISR_TUE1, }; static struct fsl_ssi_soc_data fsl_ssi_imx51 = { .imx = true, .offline_config = false, - .sisr_write_mask = CCSR_SSI_SISR_ROE0 | CCSR_SSI_SISR_ROE1 | - CCSR_SSI_SISR_TUE0 | CCSR_SSI_SISR_TUE1, + .sisr_write_mask = SSI_SISR_ROE0 | SSI_SISR_ROE1 | + SSI_SISR_TUE0 | SSI_SISR_TUE1, }; static const struct of_device_id fsl_ssi_ids[] = { @@ -354,12 +354,12 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) __be32 sisr; __be32 sisr2; - regmap_read(regs, CCSR_SSI_SISR, &sisr); + regmap_read(regs, REG_SSI_SISR, &sisr); sisr2 = sisr & ssi->soc->sisr_write_mask; /* Clear the bits that we set */ if (sisr2) - regmap_write(regs, CCSR_SSI_SISR, sisr2); + regmap_write(regs, REG_SSI_SISR, sisr2); fsl_ssi_dbg_isr(&ssi->dbg_stats, sisr); @@ -375,21 +375,21 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) struct fsl_ssi_rxtx_reg_val *vals = &ssi->rxtx_reg_val; if (enable) { - regmap_update_bits(regs, CCSR_SSI_SIER, + regmap_update_bits(regs, REG_SSI_SIER, vals->rx.sier | vals->tx.sier, vals->rx.sier | vals->tx.sier); - regmap_update_bits(regs, CCSR_SSI_SRCR, + regmap_update_bits(regs, REG_SSI_SRCR, vals->rx.srcr | vals->tx.srcr, vals->rx.srcr | vals->tx.srcr); - regmap_update_bits(regs, CCSR_SSI_STCR, + regmap_update_bits(regs, REG_SSI_STCR, vals->rx.stcr | vals->tx.stcr, vals->rx.stcr | vals->tx.stcr); } else { - regmap_update_bits(regs, CCSR_SSI_SRCR, + regmap_update_bits(regs, REG_SSI_SRCR, vals->rx.srcr | vals->tx.srcr, 0); - regmap_update_bits(regs, CCSR_SSI_STCR, + regmap_update_bits(regs, REG_SSI_STCR, vals->rx.stcr | vals->tx.stcr, 0); - regmap_update_bits(regs, CCSR_SSI_SIER, + regmap_update_bits(regs, REG_SSI_SIER, vals->rx.sier | vals->tx.sier, 0); } } @@ -400,11 +400,11 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) { if (is_rx) { - regmap_update_bits(ssi->regs, CCSR_SSI_SOR, - CCSR_SSI_SOR_RX_CLR, CCSR_SSI_SOR_RX_CLR); + regmap_update_bits(ssi->regs, REG_SSI_SOR, + SSI_SOR_RX_CLR, SSI_SOR_RX_CLR); } else { - regmap_update_bits(ssi->regs, CCSR_SSI_SOR, - CCSR_SSI_SOR_TX_CLR, CCSR_SSI_SOR_TX_CLR); + regmap_update_bits(ssi->regs, REG_SSI_SOR, + SSI_SOR_TX_CLR, SSI_SOR_TX_CLR); } } @@ -440,10 +440,10 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, u32 scr_val; int keep_active; - regmap_read(regs, CCSR_SSI_SCR, &scr_val); + regmap_read(regs, REG_SSI_SCR, &scr_val); - nr_active_streams = !!(scr_val & CCSR_SSI_SCR_TE) + - !!(scr_val & CCSR_SSI_SCR_RE); + nr_active_streams = !!(scr_val & SSI_SCR_TE) + + !!(scr_val & SSI_SCR_RE); if (nr_active_streams - 1 > 0) keep_active = 1; @@ -464,7 +464,7 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, u32 scr = fsl_ssi_disable_val(vals->scr, avals->scr, keep_active); /* Safely disable SCR register for the stream */ - regmap_update_bits(regs, CCSR_SSI_SCR, scr, 0); + regmap_update_bits(regs, REG_SSI_SCR, scr, 0); } /* @@ -483,11 +483,11 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, /* Online configure single direction while SSI is running */ if (enable) { - fsl_ssi_fifo_clear(ssi, vals->scr & CCSR_SSI_SCR_RE); + fsl_ssi_fifo_clear(ssi, vals->scr & SSI_SCR_RE); - regmap_update_bits(regs, CCSR_SSI_SRCR, vals->srcr, vals->srcr); - regmap_update_bits(regs, CCSR_SSI_STCR, vals->stcr, vals->stcr); - regmap_update_bits(regs, CCSR_SSI_SIER, vals->sier, vals->sier); + regmap_update_bits(regs, REG_SSI_SRCR, vals->srcr, vals->srcr); + regmap_update_bits(regs, REG_SSI_STCR, vals->stcr, vals->stcr); + regmap_update_bits(regs, REG_SSI_SIER, vals->sier, vals->sier); } else { u32 sier; u32 srcr; @@ -505,9 +505,9 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, keep_active); /* Safely disable other control registers for the stream */ - regmap_update_bits(regs, CCSR_SSI_SRCR, srcr, 0); - regmap_update_bits(regs, CCSR_SSI_STCR, stcr, 0); - regmap_update_bits(regs, CCSR_SSI_SIER, sier, 0); + regmap_update_bits(regs, REG_SSI_SRCR, srcr, 0); + regmap_update_bits(regs, REG_SSI_STCR, stcr, 0); + regmap_update_bits(regs, REG_SSI_SIER, sier, 0); } config_done: @@ -519,19 +519,19 @@ config_done: * * TODO: FIQ cases might also need this upon testing */ - if (ssi->use_dma && (vals->scr & CCSR_SSI_SCR_TE)) { + if (ssi->use_dma && (vals->scr & SSI_SCR_TE)) { int i; int max_loop = 100; /* Enable SSI first to send TX DMA request */ - regmap_update_bits(regs, CCSR_SSI_SCR, - CCSR_SSI_SCR_SSIEN, CCSR_SSI_SCR_SSIEN); + regmap_update_bits(regs, REG_SSI_SCR, + SSI_SCR_SSIEN, SSI_SCR_SSIEN); /* Busy wait until TX FIFO not empty -- DMA working */ for (i = 0; i < max_loop; i++) { u32 sfcsr; - regmap_read(regs, CCSR_SSI_SFCSR, &sfcsr); - if (CCSR_SSI_SFCSR_TFCNT0(sfcsr)) + regmap_read(regs, REG_SSI_SFCSR, &sfcsr); + if (SSI_SFCSR_TFCNT0(sfcsr)) break; } if (i == max_loop) { @@ -540,7 +540,7 @@ config_done: } } /* Enable all remaining bits */ - regmap_update_bits(regs, CCSR_SSI_SCR, vals->scr, vals->scr); + regmap_update_bits(regs, REG_SSI_SCR, vals->scr, vals->scr); } } @@ -557,9 +557,9 @@ static void fsl_ssi_tx_ac97_saccst_setup(struct fsl_ssi *ssi) /* no SACC{ST,EN,DIS} regs on imx21-class SSI */ if (!ssi->soc->imx21regs) { /* Disable all channel slots */ - regmap_write(regs, CCSR_SSI_SACCDIS, 0xff); + regmap_write(regs, REG_SSI_SACCDIS, 0xff); /* Enable slots 3 & 4 -- PCM Playback Left & Right channels */ - regmap_write(regs, CCSR_SSI_SACCEN, 0x300); + regmap_write(regs, REG_SSI_SACCEN, 0x300); } } @@ -585,25 +585,25 @@ static void fsl_ssi_setup_reg_vals(struct fsl_ssi *ssi) { struct fsl_ssi_rxtx_reg_val *reg = &ssi->rxtx_reg_val; - reg->rx.sier = CCSR_SSI_SIER_RFF0_EN; - reg->rx.srcr = CCSR_SSI_SRCR_RFEN0; + reg->rx.sier = SSI_SIER_RFF0_EN; + reg->rx.srcr = SSI_SRCR_RFEN0; reg->rx.scr = 0; - reg->tx.sier = CCSR_SSI_SIER_TFE0_EN; - reg->tx.stcr = CCSR_SSI_STCR_TFEN0; + reg->tx.sier = SSI_SIER_TFE0_EN; + reg->tx.stcr = SSI_STCR_TFEN0; reg->tx.scr = 0; /* AC97 has already enabled SSIEN, RE and TE, so ignore them */ if (!fsl_ssi_is_ac97(ssi)) { - reg->rx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE; - reg->tx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE; + reg->rx.scr = SSI_SCR_SSIEN | SSI_SCR_RE; + reg->tx.scr = SSI_SCR_SSIEN | SSI_SCR_TE; } if (ssi->use_dma) { - reg->rx.sier |= CCSR_SSI_SIER_RDMAE; - reg->tx.sier |= CCSR_SSI_SIER_TDMAE; + reg->rx.sier |= SSI_SIER_RDMAE; + reg->tx.sier |= SSI_SIER_TDMAE; } else { - reg->rx.sier |= CCSR_SSI_SIER_RIE; - reg->tx.sier |= CCSR_SSI_SIER_TIE; + reg->rx.sier |= SSI_SIER_RIE; + reg->tx.sier |= SSI_SIER_TIE; } reg->rx.sier |= FSLSSI_SIER_DBG_RX_FLAGS; @@ -615,21 +615,21 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi *ssi) struct regmap *regs = ssi->regs; /* Setup the clock control register */ - regmap_write(regs, CCSR_SSI_STCCR, - CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13)); - regmap_write(regs, CCSR_SSI_SRCCR, - CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13)); + regmap_write(regs, REG_SSI_STCCR, + SSI_SxCCR_WL(17) | SSI_SxCCR_DC(13)); + regmap_write(regs, REG_SSI_SRCCR, + SSI_SxCCR_WL(17) | SSI_SxCCR_DC(13)); /* Enable AC97 mode and startup the SSI */ - regmap_write(regs, CCSR_SSI_SACNT, - CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV); + regmap_write(regs, REG_SSI_SACNT, + SSI_SACNT_AC97EN | SSI_SACNT_FV); /* AC97 has to communicate with codec before starting a stream */ - regmap_update_bits(regs, CCSR_SSI_SCR, - CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE, - CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE); + regmap_update_bits(regs, REG_SSI_SCR, + SSI_SCR_SSIEN | SSI_SCR_TE | SSI_SCR_RE, + SSI_SCR_SSIEN | SSI_SCR_TE | SSI_SCR_RE); - regmap_write(regs, CCSR_SSI_SOR, CCSR_SSI_SOR_WAIT(3)); + regmap_write(regs, REG_SSI_SOR, SSI_SOR_WAIT(3)); } static int fsl_ssi_startup(struct snd_pcm_substream *substream, @@ -762,15 +762,15 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, return -EINVAL; } - stccr = CCSR_SSI_SxCCR_PM(pm + 1) | (div2 ? CCSR_SSI_SxCCR_DIV2 : 0) | - (psr ? CCSR_SSI_SxCCR_PSR : 0); - mask = CCSR_SSI_SxCCR_PM_MASK | CCSR_SSI_SxCCR_DIV2 | - CCSR_SSI_SxCCR_PSR; + stccr = SSI_SxCCR_PM(pm + 1) | (div2 ? SSI_SxCCR_DIV2 : 0) | + (psr ? SSI_SxCCR_PSR : 0); + mask = SSI_SxCCR_PM_MASK | SSI_SxCCR_DIV2 | + SSI_SxCCR_PSR; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || synchronous) - regmap_update_bits(regs, CCSR_SSI_STCCR, mask, stccr); + regmap_update_bits(regs, REG_SSI_STCCR, mask, stccr); else - regmap_update_bits(regs, CCSR_SSI_SRCCR, mask, stccr); + regmap_update_bits(regs, REG_SSI_SRCCR, mask, stccr); if (!baudclk_is_used) { ret = clk_set_rate(ssi->baudclk, baudrate); @@ -801,13 +801,13 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, struct regmap *regs = ssi->regs; unsigned int channels = params_channels(hw_params); unsigned int sample_size = params_width(hw_params); - u32 wl = CCSR_SSI_SxCCR_WL(sample_size); + u32 wl = SSI_SxCCR_WL(sample_size); int ret; u32 scr_val; int enabled; - regmap_read(regs, CCSR_SSI_SCR, &scr_val); - enabled = scr_val & CCSR_SSI_SCR_SSIEN; + regmap_read(regs, REG_SSI_SCR, &scr_val); + enabled = scr_val & SSI_SCR_SSIEN; /* * SSI is properly configured if it is enabled and running in @@ -837,23 +837,23 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, u8 i2smode; /* Normal + Network mode to send 16-bit data in 32-bit frames */ if (fsl_ssi_is_i2s_cbm_cfs(ssi) && sample_size == 16) - i2smode = CCSR_SSI_SCR_I2S_MODE_NORMAL | - CCSR_SSI_SCR_NET; + i2smode = SSI_SCR_I2S_MODE_NORMAL | + SSI_SCR_NET; else i2smode = ssi->i2s_mode; - regmap_update_bits(regs, CCSR_SSI_SCR, - CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK, + regmap_update_bits(regs, REG_SSI_SCR, + SSI_SCR_NET | SSI_SCR_I2S_MODE_MASK, channels == 1 ? 0 : i2smode); } /* In synchronous mode, the SSI uses STCCR for capture */ if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) || ssi->cpu_dai_drv.symmetric_rates) - regmap_update_bits(regs, CCSR_SSI_STCCR, CCSR_SSI_SxCCR_WL_MASK, + regmap_update_bits(regs, REG_SSI_STCCR, SSI_SxCCR_WL_MASK, wl); else - regmap_update_bits(regs, CCSR_SSI_SRCCR, CCSR_SSI_SxCCR_WL_MASK, + regmap_update_bits(regs, REG_SSI_SRCCR, SSI_SxCCR_WL_MASK, wl); return 0; @@ -890,62 +890,62 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, fsl_ssi_setup_reg_vals(ssi); - regmap_read(regs, CCSR_SSI_SCR, &scr); - scr &= ~(CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_I2S_MODE_MASK); + regmap_read(regs, REG_SSI_SCR, &scr); + scr &= ~(SSI_SCR_SYN | SSI_SCR_I2S_MODE_MASK); /* Synchronize frame sync clock for TE to avoid data slipping */ - scr |= CCSR_SSI_SCR_SYNC_TX_FS; + scr |= SSI_SCR_SYNC_TX_FS; - mask = CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR | - CCSR_SSI_STCR_TSCKP | CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TFSL | - CCSR_SSI_STCR_TEFS; - regmap_read(regs, CCSR_SSI_STCR, &stcr); - regmap_read(regs, CCSR_SSI_SRCR, &srcr); + mask = SSI_STCR_TXBIT0 | SSI_STCR_TFDIR | SSI_STCR_TXDIR | + SSI_STCR_TSCKP | SSI_STCR_TFSI | SSI_STCR_TFSL | + SSI_STCR_TEFS; + regmap_read(regs, REG_SSI_STCR, &stcr); + regmap_read(regs, REG_SSI_SRCR, &srcr); stcr &= ~mask; srcr &= ~mask; /* Use Network mode as default */ - ssi->i2s_mode = CCSR_SSI_SCR_NET; + ssi->i2s_mode = SSI_SCR_NET; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: - regmap_update_bits(regs, CCSR_SSI_STCCR, - CCSR_SSI_SxCCR_DC_MASK, - CCSR_SSI_SxCCR_DC(2)); - regmap_update_bits(regs, CCSR_SSI_SRCCR, - CCSR_SSI_SxCCR_DC_MASK, - CCSR_SSI_SxCCR_DC(2)); + regmap_update_bits(regs, REG_SSI_STCCR, + SSI_SxCCR_DC_MASK, + SSI_SxCCR_DC(2)); + regmap_update_bits(regs, REG_SSI_SRCCR, + SSI_SxCCR_DC_MASK, + SSI_SxCCR_DC(2)); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFS: case SND_SOC_DAIFMT_CBS_CFS: - ssi->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER; + ssi->i2s_mode |= SSI_SCR_I2S_MODE_MASTER; break; case SND_SOC_DAIFMT_CBM_CFM: - ssi->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_SLAVE; + ssi->i2s_mode |= SSI_SCR_I2S_MODE_SLAVE; break; default: return -EINVAL; } /* Data on rising edge of bclk, frame low, 1clk before data */ - strcr |= CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TSCKP | - CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TEFS; + strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP | + SSI_STCR_TXBIT0 | SSI_STCR_TEFS; break; case SND_SOC_DAIFMT_LEFT_J: /* Data on rising edge of bclk, frame high */ - strcr |= CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TSCKP; + strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP; break; case SND_SOC_DAIFMT_DSP_A: /* Data on rising edge of bclk, frame high, 1clk before data */ - strcr |= CCSR_SSI_STCR_TFSL | CCSR_SSI_STCR_TSCKP | - CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TEFS; + strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP | + SSI_STCR_TXBIT0 | SSI_STCR_TEFS; break; case SND_SOC_DAIFMT_DSP_B: /* Data on rising edge of bclk, frame high */ - strcr |= CCSR_SSI_STCR_TFSL | CCSR_SSI_STCR_TSCKP | - CCSR_SSI_STCR_TXBIT0; + strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP | + SSI_STCR_TXBIT0; break; case SND_SOC_DAIFMT_AC97: /* Data on falling edge of bclk, frame high, 1clk before data */ - ssi->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_NORMAL; + ssi->i2s_mode |= SSI_SCR_I2S_MODE_NORMAL; break; default: return -EINVAL; @@ -959,16 +959,16 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, break; case SND_SOC_DAIFMT_IB_NF: /* Invert bit clock */ - strcr ^= CCSR_SSI_STCR_TSCKP; + strcr ^= SSI_STCR_TSCKP; break; case SND_SOC_DAIFMT_NB_IF: /* Invert frame clock */ - strcr ^= CCSR_SSI_STCR_TFSI; + strcr ^= SSI_STCR_TFSI; break; case SND_SOC_DAIFMT_IB_IF: /* Invert both clocks */ - strcr ^= CCSR_SSI_STCR_TSCKP; - strcr ^= CCSR_SSI_STCR_TFSI; + strcr ^= SSI_STCR_TSCKP; + strcr ^= SSI_STCR_TFSI; break; default: return -EINVAL; @@ -978,18 +978,18 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: /* Output bit and frame sync clocks */ - strcr |= CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR; - scr |= CCSR_SSI_SCR_SYS_CLK_EN; + strcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR; + scr |= SSI_SCR_SYS_CLK_EN; break; case SND_SOC_DAIFMT_CBM_CFM: /* Input bit or frame sync clocks */ - scr &= ~CCSR_SSI_SCR_SYS_CLK_EN; + scr &= ~SSI_SCR_SYS_CLK_EN; break; case SND_SOC_DAIFMT_CBM_CFS: /* Input bit clock but output frame sync clock */ - strcr &= ~CCSR_SSI_STCR_TXDIR; - strcr |= CCSR_SSI_STCR_TFDIR; - scr &= ~CCSR_SSI_SCR_SYS_CLK_EN; + strcr &= ~SSI_STCR_TXDIR; + strcr |= SSI_STCR_TFDIR; + scr &= ~SSI_SCR_SYS_CLK_EN; break; default: if (!fsl_ssi_is_ac97(ssi)) @@ -1001,27 +1001,27 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, /* Set SYN mode and clear RXDIR bit when using SYN or AC97 mode */ if (ssi->cpu_dai_drv.symmetric_rates || fsl_ssi_is_ac97(ssi)) { - srcr &= ~CCSR_SSI_SRCR_RXDIR; - scr |= CCSR_SSI_SCR_SYN; + srcr &= ~SSI_SRCR_RXDIR; + scr |= SSI_SCR_SYN; } - regmap_write(regs, CCSR_SSI_STCR, stcr); - regmap_write(regs, CCSR_SSI_SRCR, srcr); - regmap_write(regs, CCSR_SSI_SCR, scr); + regmap_write(regs, REG_SSI_STCR, stcr); + regmap_write(regs, REG_SSI_SRCR, srcr); + regmap_write(regs, REG_SSI_SCR, scr); wm = ssi->fifo_watermark; - regmap_write(regs, CCSR_SSI_SFCSR, - CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) | - CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm)); + regmap_write(regs, REG_SSI_SFCSR, + SSI_SFCSR_TFWM0(wm) | SSI_SFCSR_RFWM0(wm) | + SSI_SFCSR_TFWM1(wm) | SSI_SFCSR_RFWM1(wm)); if (ssi->use_dual_fifo) { - regmap_update_bits(regs, CCSR_SSI_SRCR, CCSR_SSI_SRCR_RFEN1, - CCSR_SSI_SRCR_RFEN1); - regmap_update_bits(regs, CCSR_SSI_STCR, CCSR_SSI_STCR_TFEN1, - CCSR_SSI_STCR_TFEN1); - regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_TCH_EN, - CCSR_SSI_SCR_TCH_EN); + regmap_update_bits(regs, REG_SSI_SRCR, SSI_SRCR_RFEN1, + SSI_SRCR_RFEN1); + regmap_update_bits(regs, REG_SSI_STCR, SSI_STCR_TFEN1, + SSI_STCR_TFEN1); + regmap_update_bits(regs, REG_SSI_SCR, SSI_SCR_TCH_EN, + SSI_SCR_TCH_EN); } if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_AC97) @@ -1062,30 +1062,30 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, } /* The slot number should be >= 2 if using Network mode or I2S mode */ - regmap_read(regs, CCSR_SSI_SCR, &val); - val &= CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_NET; + regmap_read(regs, REG_SSI_SCR, &val); + val &= SSI_SCR_I2S_MODE_MASK | SSI_SCR_NET; if (val && slots < 2) { dev_err(cpu_dai->dev, "slot number should be >= 2 in I2S or NET\n"); return -EINVAL; } - regmap_update_bits(regs, CCSR_SSI_STCCR, CCSR_SSI_SxCCR_DC_MASK, - CCSR_SSI_SxCCR_DC(slots)); - regmap_update_bits(regs, CCSR_SSI_SRCCR, CCSR_SSI_SxCCR_DC_MASK, - CCSR_SSI_SxCCR_DC(slots)); + regmap_update_bits(regs, REG_SSI_STCCR, SSI_SxCCR_DC_MASK, + SSI_SxCCR_DC(slots)); + regmap_update_bits(regs, REG_SSI_SRCCR, SSI_SxCCR_DC_MASK, + SSI_SxCCR_DC(slots)); /* Save SSIEN bit of the SCR register */ - regmap_read(regs, CCSR_SSI_SCR, &val); - val &= CCSR_SSI_SCR_SSIEN; + regmap_read(regs, REG_SSI_SCR, &val); + val &= SSI_SCR_SSIEN; /* Temporarily enable SSI to allow SxMSKs to be configurable */ - regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN, - CCSR_SSI_SCR_SSIEN); + regmap_update_bits(regs, REG_SSI_SCR, SSI_SCR_SSIEN, + SSI_SCR_SSIEN); - regmap_write(regs, CCSR_SSI_STMSK, ~tx_mask); - regmap_write(regs, CCSR_SSI_SRMSK, ~rx_mask); + regmap_write(regs, REG_SSI_STMSK, ~tx_mask); + regmap_write(regs, REG_SSI_SRMSK, ~rx_mask); /* Restore the value of SSIEN bit */ - regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN, val); + regmap_update_bits(regs, REG_SSI_SCR, SSI_SCR_SSIEN, val); ssi->slot_width = slot_width; ssi->slots = slots; @@ -1132,9 +1132,9 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, /* Clear corresponding FIFO */ if (fsl_ssi_is_ac97(ssi)) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - regmap_write(regs, CCSR_SSI_SOR, CCSR_SSI_SOR_TX_CLR); + regmap_write(regs, REG_SSI_SOR, SSI_SOR_TX_CLR); else - regmap_write(regs, CCSR_SSI_SOR, CCSR_SSI_SOR_RX_CLR); + regmap_write(regs, REG_SSI_SOR, SSI_SOR_RX_CLR); } return 0; @@ -1230,13 +1230,13 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, } lreg = reg << 12; - regmap_write(regs, CCSR_SSI_SACADD, lreg); + regmap_write(regs, REG_SSI_SACADD, lreg); lval = val << 4; - regmap_write(regs, CCSR_SSI_SACDAT, lval); + regmap_write(regs, REG_SSI_SACDAT, lval); - regmap_update_bits(regs, CCSR_SSI_SACNT, CCSR_SSI_SACNT_RDWR_MASK, - CCSR_SSI_SACNT_WR); + regmap_update_bits(regs, REG_SSI_SACNT, SSI_SACNT_RDWR_MASK, + SSI_SACNT_WR); udelay(100); clk_disable_unprepare(fsl_ac97_data->clk); @@ -1265,13 +1265,13 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, } lreg = (reg & 0x7f) << 12; - regmap_write(regs, CCSR_SSI_SACADD, lreg); - regmap_update_bits(regs, CCSR_SSI_SACNT, CCSR_SSI_SACNT_RDWR_MASK, - CCSR_SSI_SACNT_RD); + regmap_write(regs, REG_SSI_SACADD, lreg); + regmap_update_bits(regs, REG_SSI_SACNT, SSI_SACNT_RDWR_MASK, + SSI_SACNT_RD); udelay(100); - regmap_read(regs, CCSR_SSI_SACDAT, ®_val); + regmap_read(regs, REG_SSI_SACDAT, ®_val); val = (reg_val >> 4) & 0xffff; clk_disable_unprepare(fsl_ac97_data->clk); @@ -1333,8 +1333,8 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, ssi->dma_params_tx.maxburst = ssi->dma_maxburst; ssi->dma_params_rx.maxburst = ssi->dma_maxburst; - ssi->dma_params_tx.addr = ssi->ssi_phys + CCSR_SSI_STX0; - ssi->dma_params_rx.addr = ssi->ssi_phys + CCSR_SSI_SRX0; + ssi->dma_params_tx.addr = ssi->ssi_phys + REG_SSI_STX0; + ssi->dma_params_rx.addr = ssi->ssi_phys + REG_SSI_SRX0; /* Set to dual FIFO mode according to the SDMA sciprt */ ret = of_property_read_u32_array(np, "dmas", dmas, 4); @@ -1439,9 +1439,9 @@ static int fsl_ssi_probe(struct platform_device *pdev) if (ssi->soc->imx21regs) { /* No SACC{ST,EN,DIS} regs in imx21-class SSI */ - regconfig.max_register = CCSR_SSI_SRMSK; + regconfig.max_register = REG_SSI_SRMSK; regconfig.num_reg_defaults_raw = - CCSR_SSI_SRMSK / sizeof(uint32_t) + 1; + REG_SSI_SRMSK / sizeof(uint32_t) + 1; } ret = of_property_match_string(np, "clock-names", "ipg"); @@ -1638,8 +1638,8 @@ static int fsl_ssi_suspend(struct device *dev) struct fsl_ssi *ssi = dev_get_drvdata(dev); struct regmap *regs = ssi->regs; - regmap_read(regs, CCSR_SSI_SFCSR, &ssi->regcache_sfcsr); - regmap_read(regs, CCSR_SSI_SACNT, &ssi->regcache_sacnt); + regmap_read(regs, REG_SSI_SFCSR, &ssi->regcache_sfcsr); + regmap_read(regs, REG_SSI_SACNT, &ssi->regcache_sacnt); regcache_cache_only(regs, true); regcache_mark_dirty(regs); @@ -1654,11 +1654,11 @@ static int fsl_ssi_resume(struct device *dev) regcache_cache_only(regs, false); - regmap_update_bits(regs, CCSR_SSI_SFCSR, - CCSR_SSI_SFCSR_RFWM1_MASK | CCSR_SSI_SFCSR_TFWM1_MASK | - CCSR_SSI_SFCSR_RFWM0_MASK | CCSR_SSI_SFCSR_TFWM0_MASK, + regmap_update_bits(regs, REG_SSI_SFCSR, + SSI_SFCSR_RFWM1_MASK | SSI_SFCSR_TFWM1_MASK | + SSI_SFCSR_RFWM0_MASK | SSI_SFCSR_TFWM0_MASK, ssi->regcache_sfcsr); - regmap_write(regs, CCSR_SSI_SACNT, ssi->regcache_sacnt); + regmap_write(regs, REG_SSI_SACNT, ssi->regcache_sacnt); return regcache_sync(regs); } diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h index 1ad3bde7f065..cdcf3d23873e 100644 --- a/sound/soc/fsl/fsl_ssi.h +++ b/sound/soc/fsl/fsl_ssi.h @@ -15,55 +15,55 @@ /* -- SSI Register Map -- */ /* SSI Transmit Data Register 0 */ -#define CCSR_SSI_STX0 0x00 +#define REG_SSI_STX0 0x00 /* SSI Transmit Data Register 1 */ -#define CCSR_SSI_STX1 0x04 +#define REG_SSI_STX1 0x04 /* SSI Receive Data Register 0 */ -#define CCSR_SSI_SRX0 0x08 +#define REG_SSI_SRX0 0x08 /* SSI Receive Data Register 1 */ -#define CCSR_SSI_SRX1 0x0c +#define REG_SSI_SRX1 0x0c /* SSI Control Register */ -#define CCSR_SSI_SCR 0x10 +#define REG_SSI_SCR 0x10 /* SSI Interrupt Status Register */ -#define CCSR_SSI_SISR 0x14 +#define REG_SSI_SISR 0x14 /* SSI Interrupt Enable Register */ -#define CCSR_SSI_SIER 0x18 +#define REG_SSI_SIER 0x18 /* SSI Transmit Configuration Register */ -#define CCSR_SSI_STCR 0x1c +#define REG_SSI_STCR 0x1c /* SSI Receive Configuration Register */ -#define CCSR_SSI_SRCR 0x20 +#define REG_SSI_SRCR 0x20 /* SSI Transmit Clock Control Register */ -#define CCSR_SSI_STCCR 0x24 +#define REG_SSI_STCCR 0x24 /* SSI Receive Clock Control Register */ -#define CCSR_SSI_SRCCR 0x28 +#define REG_SSI_SRCCR 0x28 /* SSI FIFO Control/Status Register */ -#define CCSR_SSI_SFCSR 0x2c +#define REG_SSI_SFCSR 0x2c /* * SSI Test Register (Intended for debugging purposes only) * * Note: STR is not documented in recent IMX datasheet, but * is described in IMX51 reference manual at section 56.3.3.14 */ -#define CCSR_SSI_STR 0x30 +#define REG_SSI_STR 0x30 /* * SSI Option Register (Intended for internal use only) * * Note: SOR is not documented in recent IMX datasheet, but * is described in IMX51 reference manual at section 56.3.3.15 */ -#define CCSR_SSI_SOR 0x34 +#define REG_SSI_SOR 0x34 /* SSI AC97 Control Register */ -#define CCSR_SSI_SACNT 0x38 +#define REG_SSI_SACNT 0x38 /* SSI AC97 Command Address Register */ -#define CCSR_SSI_SACADD 0x3c +#define REG_SSI_SACADD 0x3c /* SSI AC97 Command Data Register */ -#define CCSR_SSI_SACDAT 0x40 +#define REG_SSI_SACDAT 0x40 /* SSI AC97 Tag Register */ -#define CCSR_SSI_SATAG 0x44 +#define REG_SSI_SATAG 0x44 /* SSI Transmit Time Slot Mask Register */ -#define CCSR_SSI_STMSK 0x48 +#define REG_SSI_STMSK 0x48 /* SSI Receive Time Slot Mask Register */ -#define CCSR_SSI_SRMSK 0x4c +#define REG_SSI_SRMSK 0x4c /* * SSI AC97 Channel Status Register * @@ -72,193 +72,193 @@ * 2) Writing a '1' bit at some position in SACCDIS unsets the relevant bit * 3) Receivng a '1' in SLOTREQ bit from external CODEC via AC Link */ -#define CCSR_SSI_SACCST 0x50 +#define REG_SSI_SACCST 0x50 /* SSI AC97 Channel Enable Register -- Set bits in SACCST */ -#define CCSR_SSI_SACCEN 0x54 +#define REG_SSI_SACCEN 0x54 /* SSI AC97 Channel Disable Register -- Clear bits in SACCST */ -#define CCSR_SSI_SACCDIS 0x58 +#define REG_SSI_SACCDIS 0x58 /* -- SSI Register Field Maps -- */ -/* SSI Control Register -- CCSR_SSI_SCR 0x10 */ -#define CCSR_SSI_SCR_SYNC_TX_FS 0x00001000 -#define CCSR_SSI_SCR_RFR_CLK_DIS 0x00000800 -#define CCSR_SSI_SCR_TFR_CLK_DIS 0x00000400 -#define CCSR_SSI_SCR_TCH_EN 0x00000100 -#define CCSR_SSI_SCR_SYS_CLK_EN 0x00000080 -#define CCSR_SSI_SCR_I2S_MODE_MASK 0x00000060 -#define CCSR_SSI_SCR_I2S_MODE_NORMAL 0x00000000 -#define CCSR_SSI_SCR_I2S_MODE_MASTER 0x00000020 -#define CCSR_SSI_SCR_I2S_MODE_SLAVE 0x00000040 -#define CCSR_SSI_SCR_SYN 0x00000010 -#define CCSR_SSI_SCR_NET 0x00000008 -#define CCSR_SSI_SCR_RE 0x00000004 -#define CCSR_SSI_SCR_TE 0x00000002 -#define CCSR_SSI_SCR_SSIEN 0x00000001 +/* SSI Control Register -- REG_SSI_SCR 0x10 */ +#define SSI_SCR_SYNC_TX_FS 0x00001000 +#define SSI_SCR_RFR_CLK_DIS 0x00000800 +#define SSI_SCR_TFR_CLK_DIS 0x00000400 +#define SSI_SCR_TCH_EN 0x00000100 +#define SSI_SCR_SYS_CLK_EN 0x00000080 +#define SSI_SCR_I2S_MODE_MASK 0x00000060 +#define SSI_SCR_I2S_MODE_NORMAL 0x00000000 +#define SSI_SCR_I2S_MODE_MASTER 0x00000020 +#define SSI_SCR_I2S_MODE_SLAVE 0x00000040 +#define SSI_SCR_SYN 0x00000010 +#define SSI_SCR_NET 0x00000008 +#define SSI_SCR_RE 0x00000004 +#define SSI_SCR_TE 0x00000002 +#define SSI_SCR_SSIEN 0x00000001 -/* SSI Interrupt Status Register -- CCSR_SSI_SISR 0x14 */ -#define CCSR_SSI_SISR_RFRC 0x01000000 -#define CCSR_SSI_SISR_TFRC 0x00800000 -#define CCSR_SSI_SISR_CMDAU 0x00040000 -#define CCSR_SSI_SISR_CMDDU 0x00020000 -#define CCSR_SSI_SISR_RXT 0x00010000 -#define CCSR_SSI_SISR_RDR1 0x00008000 -#define CCSR_SSI_SISR_RDR0 0x00004000 -#define CCSR_SSI_SISR_TDE1 0x00002000 -#define CCSR_SSI_SISR_TDE0 0x00001000 -#define CCSR_SSI_SISR_ROE1 0x00000800 -#define CCSR_SSI_SISR_ROE0 0x00000400 -#define CCSR_SSI_SISR_TUE1 0x00000200 -#define CCSR_SSI_SISR_TUE0 0x00000100 -#define CCSR_SSI_SISR_TFS 0x00000080 -#define CCSR_SSI_SISR_RFS 0x00000040 -#define CCSR_SSI_SISR_TLS 0x00000020 -#define CCSR_SSI_SISR_RLS 0x00000010 -#define CCSR_SSI_SISR_RFF1 0x00000008 -#define CCSR_SSI_SISR_RFF0 0x00000004 -#define CCSR_SSI_SISR_TFE1 0x00000002 -#define CCSR_SSI_SISR_TFE0 0x00000001 +/* SSI Interrupt Status Register -- REG_SSI_SISR 0x14 */ +#define SSI_SISR_RFRC 0x01000000 +#define SSI_SISR_TFRC 0x00800000 +#define SSI_SISR_CMDAU 0x00040000 +#define SSI_SISR_CMDDU 0x00020000 +#define SSI_SISR_RXT 0x00010000 +#define SSI_SISR_RDR1 0x00008000 +#define SSI_SISR_RDR0 0x00004000 +#define SSI_SISR_TDE1 0x00002000 +#define SSI_SISR_TDE0 0x00001000 +#define SSI_SISR_ROE1 0x00000800 +#define SSI_SISR_ROE0 0x00000400 +#define SSI_SISR_TUE1 0x00000200 +#define SSI_SISR_TUE0 0x00000100 +#define SSI_SISR_TFS 0x00000080 +#define SSI_SISR_RFS 0x00000040 +#define SSI_SISR_TLS 0x00000020 +#define SSI_SISR_RLS 0x00000010 +#define SSI_SISR_RFF1 0x00000008 +#define SSI_SISR_RFF0 0x00000004 +#define SSI_SISR_TFE1 0x00000002 +#define SSI_SISR_TFE0 0x00000001 -/* SSI Interrupt Enable Register -- CCSR_SSI_SIER 0x18 */ -#define CCSR_SSI_SIER_RFRC_EN 0x01000000 -#define CCSR_SSI_SIER_TFRC_EN 0x00800000 -#define CCSR_SSI_SIER_RDMAE 0x00400000 -#define CCSR_SSI_SIER_RIE 0x00200000 -#define CCSR_SSI_SIER_TDMAE 0x00100000 -#define CCSR_SSI_SIER_TIE 0x00080000 -#define CCSR_SSI_SIER_CMDAU_EN 0x00040000 -#define CCSR_SSI_SIER_CMDDU_EN 0x00020000 -#define CCSR_SSI_SIER_RXT_EN 0x00010000 -#define CCSR_SSI_SIER_RDR1_EN 0x00008000 -#define CCSR_SSI_SIER_RDR0_EN 0x00004000 -#define CCSR_SSI_SIER_TDE1_EN 0x00002000 -#define CCSR_SSI_SIER_TDE0_EN 0x00001000 -#define CCSR_SSI_SIER_ROE1_EN 0x00000800 -#define CCSR_SSI_SIER_ROE0_EN 0x00000400 -#define CCSR_SSI_SIER_TUE1_EN 0x00000200 -#define CCSR_SSI_SIER_TUE0_EN 0x00000100 -#define CCSR_SSI_SIER_TFS_EN 0x00000080 -#define CCSR_SSI_SIER_RFS_EN 0x00000040 -#define CCSR_SSI_SIER_TLS_EN 0x00000020 -#define CCSR_SSI_SIER_RLS_EN 0x00000010 -#define CCSR_SSI_SIER_RFF1_EN 0x00000008 -#define CCSR_SSI_SIER_RFF0_EN 0x00000004 -#define CCSR_SSI_SIER_TFE1_EN 0x00000002 -#define CCSR_SSI_SIER_TFE0_EN 0x00000001 +/* SSI Interrupt Enable Register -- REG_SSI_SIER 0x18 */ +#define SSI_SIER_RFRC_EN 0x01000000 +#define SSI_SIER_TFRC_EN 0x00800000 +#define SSI_SIER_RDMAE 0x00400000 +#define SSI_SIER_RIE 0x00200000 +#define SSI_SIER_TDMAE 0x00100000 +#define SSI_SIER_TIE 0x00080000 +#define SSI_SIER_CMDAU_EN 0x00040000 +#define SSI_SIER_CMDDU_EN 0x00020000 +#define SSI_SIER_RXT_EN 0x00010000 +#define SSI_SIER_RDR1_EN 0x00008000 +#define SSI_SIER_RDR0_EN 0x00004000 +#define SSI_SIER_TDE1_EN 0x00002000 +#define SSI_SIER_TDE0_EN 0x00001000 +#define SSI_SIER_ROE1_EN 0x00000800 +#define SSI_SIER_ROE0_EN 0x00000400 +#define SSI_SIER_TUE1_EN 0x00000200 +#define SSI_SIER_TUE0_EN 0x00000100 +#define SSI_SIER_TFS_EN 0x00000080 +#define SSI_SIER_RFS_EN 0x00000040 +#define SSI_SIER_TLS_EN 0x00000020 +#define SSI_SIER_RLS_EN 0x00000010 +#define SSI_SIER_RFF1_EN 0x00000008 +#define SSI_SIER_RFF0_EN 0x00000004 +#define SSI_SIER_TFE1_EN 0x00000002 +#define SSI_SIER_TFE0_EN 0x00000001 -/* SSI Transmit Configuration Register -- CCSR_SSI_STCR 0x1C */ -#define CCSR_SSI_STCR_TXBIT0 0x00000200 -#define CCSR_SSI_STCR_TFEN1 0x00000100 -#define CCSR_SSI_STCR_TFEN0 0x00000080 -#define CCSR_SSI_STCR_TFDIR 0x00000040 -#define CCSR_SSI_STCR_TXDIR 0x00000020 -#define CCSR_SSI_STCR_TSHFD 0x00000010 -#define CCSR_SSI_STCR_TSCKP 0x00000008 -#define CCSR_SSI_STCR_TFSI 0x00000004 -#define CCSR_SSI_STCR_TFSL 0x00000002 -#define CCSR_SSI_STCR_TEFS 0x00000001 +/* SSI Transmit Configuration Register -- REG_SSI_STCR 0x1C */ +#define SSI_STCR_TXBIT0 0x00000200 +#define SSI_STCR_TFEN1 0x00000100 +#define SSI_STCR_TFEN0 0x00000080 +#define SSI_STCR_TFDIR 0x00000040 +#define SSI_STCR_TXDIR 0x00000020 +#define SSI_STCR_TSHFD 0x00000010 +#define SSI_STCR_TSCKP 0x00000008 +#define SSI_STCR_TFSI 0x00000004 +#define SSI_STCR_TFSL 0x00000002 +#define SSI_STCR_TEFS 0x00000001 -/* SSI Receive Configuration Register -- CCSR_SSI_SRCR 0x20 */ -#define CCSR_SSI_SRCR_RXEXT 0x00000400 -#define CCSR_SSI_SRCR_RXBIT0 0x00000200 -#define CCSR_SSI_SRCR_RFEN1 0x00000100 -#define CCSR_SSI_SRCR_RFEN0 0x00000080 -#define CCSR_SSI_SRCR_RFDIR 0x00000040 -#define CCSR_SSI_SRCR_RXDIR 0x00000020 -#define CCSR_SSI_SRCR_RSHFD 0x00000010 -#define CCSR_SSI_SRCR_RSCKP 0x00000008 -#define CCSR_SSI_SRCR_RFSI 0x00000004 -#define CCSR_SSI_SRCR_RFSL 0x00000002 -#define CCSR_SSI_SRCR_REFS 0x00000001 +/* SSI Receive Configuration Register -- REG_SSI_SRCR 0x20 */ +#define SSI_SRCR_RXEXT 0x00000400 +#define SSI_SRCR_RXBIT0 0x00000200 +#define SSI_SRCR_RFEN1 0x00000100 +#define SSI_SRCR_RFEN0 0x00000080 +#define SSI_SRCR_RFDIR 0x00000040 +#define SSI_SRCR_RXDIR 0x00000020 +#define SSI_SRCR_RSHFD 0x00000010 +#define SSI_SRCR_RSCKP 0x00000008 +#define SSI_SRCR_RFSI 0x00000004 +#define SSI_SRCR_RFSL 0x00000002 +#define SSI_SRCR_REFS 0x00000001 /* - * SSI Transmit Clock Control Register -- CCSR_SSI_STCCR 0x24 - * SSI Receive Clock Control Register -- CCSR_SSI_SRCCR 0x28 + * SSI Transmit Clock Control Register -- REG_SSI_STCCR 0x24 + * SSI Receive Clock Control Register -- REG_SSI_SRCCR 0x28 */ -#define CCSR_SSI_SxCCR_DIV2_SHIFT 18 -#define CCSR_SSI_SxCCR_DIV2 0x00040000 -#define CCSR_SSI_SxCCR_PSR_SHIFT 17 -#define CCSR_SSI_SxCCR_PSR 0x00020000 -#define CCSR_SSI_SxCCR_WL_SHIFT 13 -#define CCSR_SSI_SxCCR_WL_MASK 0x0001E000 -#define CCSR_SSI_SxCCR_WL(x) \ - (((((x) / 2) - 1) << CCSR_SSI_SxCCR_WL_SHIFT) & CCSR_SSI_SxCCR_WL_MASK) -#define CCSR_SSI_SxCCR_DC_SHIFT 8 -#define CCSR_SSI_SxCCR_DC_MASK 0x00001F00 -#define CCSR_SSI_SxCCR_DC(x) \ - ((((x) - 1) << CCSR_SSI_SxCCR_DC_SHIFT) & CCSR_SSI_SxCCR_DC_MASK) -#define CCSR_SSI_SxCCR_PM_SHIFT 0 -#define CCSR_SSI_SxCCR_PM_MASK 0x000000FF -#define CCSR_SSI_SxCCR_PM(x) \ - ((((x) - 1) << CCSR_SSI_SxCCR_PM_SHIFT) & CCSR_SSI_SxCCR_PM_MASK) +#define SSI_SxCCR_DIV2_SHIFT 18 +#define SSI_SxCCR_DIV2 0x00040000 +#define SSI_SxCCR_PSR_SHIFT 17 +#define SSI_SxCCR_PSR 0x00020000 +#define SSI_SxCCR_WL_SHIFT 13 +#define SSI_SxCCR_WL_MASK 0x0001E000 +#define SSI_SxCCR_WL(x) \ + (((((x) / 2) - 1) << SSI_SxCCR_WL_SHIFT) & SSI_SxCCR_WL_MASK) +#define SSI_SxCCR_DC_SHIFT 8 +#define SSI_SxCCR_DC_MASK 0x00001F00 +#define SSI_SxCCR_DC(x) \ + ((((x) - 1) << SSI_SxCCR_DC_SHIFT) & SSI_SxCCR_DC_MASK) +#define SSI_SxCCR_PM_SHIFT 0 +#define SSI_SxCCR_PM_MASK 0x000000FF +#define SSI_SxCCR_PM(x) \ + ((((x) - 1) << SSI_SxCCR_PM_SHIFT) & SSI_SxCCR_PM_MASK) /* - * SSI FIFO Control/Status Register -- CCSR_SSI_SFCSR 0x2c + * SSI FIFO Control/Status Register -- REG_SSI_SFCSR 0x2c * - * Tx or Rx FIFO Counter -- CCSR_SSI_SFCSR_xFCNTy Read-Only - * Tx or Rx FIFO Watermarks -- CCSR_SSI_SFCSR_xFWMy Read/Write + * Tx or Rx FIFO Counter -- SSI_SFCSR_xFCNTy Read-Only + * Tx or Rx FIFO Watermarks -- SSI_SFCSR_xFWMy Read/Write */ -#define CCSR_SSI_SFCSR_RFCNT1_SHIFT 28 -#define CCSR_SSI_SFCSR_RFCNT1_MASK 0xF0000000 -#define CCSR_SSI_SFCSR_RFCNT1(x) \ - (((x) & CCSR_SSI_SFCSR_RFCNT1_MASK) >> CCSR_SSI_SFCSR_RFCNT1_SHIFT) -#define CCSR_SSI_SFCSR_TFCNT1_SHIFT 24 -#define CCSR_SSI_SFCSR_TFCNT1_MASK 0x0F000000 -#define CCSR_SSI_SFCSR_TFCNT1(x) \ - (((x) & CCSR_SSI_SFCSR_TFCNT1_MASK) >> CCSR_SSI_SFCSR_TFCNT1_SHIFT) -#define CCSR_SSI_SFCSR_RFWM1_SHIFT 20 -#define CCSR_SSI_SFCSR_RFWM1_MASK 0x00F00000 -#define CCSR_SSI_SFCSR_RFWM1(x) \ - (((x) << CCSR_SSI_SFCSR_RFWM1_SHIFT) & CCSR_SSI_SFCSR_RFWM1_MASK) -#define CCSR_SSI_SFCSR_TFWM1_SHIFT 16 -#define CCSR_SSI_SFCSR_TFWM1_MASK 0x000F0000 -#define CCSR_SSI_SFCSR_TFWM1(x) \ - (((x) << CCSR_SSI_SFCSR_TFWM1_SHIFT) & CCSR_SSI_SFCSR_TFWM1_MASK) -#define CCSR_SSI_SFCSR_RFCNT0_SHIFT 12 -#define CCSR_SSI_SFCSR_RFCNT0_MASK 0x0000F000 -#define CCSR_SSI_SFCSR_RFCNT0(x) \ - (((x) & CCSR_SSI_SFCSR_RFCNT0_MASK) >> CCSR_SSI_SFCSR_RFCNT0_SHIFT) -#define CCSR_SSI_SFCSR_TFCNT0_SHIFT 8 -#define CCSR_SSI_SFCSR_TFCNT0_MASK 0x00000F00 -#define CCSR_SSI_SFCSR_TFCNT0(x) \ - (((x) & CCSR_SSI_SFCSR_TFCNT0_MASK) >> CCSR_SSI_SFCSR_TFCNT0_SHIFT) -#define CCSR_SSI_SFCSR_RFWM0_SHIFT 4 -#define CCSR_SSI_SFCSR_RFWM0_MASK 0x000000F0 -#define CCSR_SSI_SFCSR_RFWM0(x) \ - (((x) << CCSR_SSI_SFCSR_RFWM0_SHIFT) & CCSR_SSI_SFCSR_RFWM0_MASK) -#define CCSR_SSI_SFCSR_TFWM0_SHIFT 0 -#define CCSR_SSI_SFCSR_TFWM0_MASK 0x0000000F -#define CCSR_SSI_SFCSR_TFWM0(x) \ - (((x) << CCSR_SSI_SFCSR_TFWM0_SHIFT) & CCSR_SSI_SFCSR_TFWM0_MASK) +#define SSI_SFCSR_RFCNT1_SHIFT 28 +#define SSI_SFCSR_RFCNT1_MASK 0xF0000000 +#define SSI_SFCSR_RFCNT1(x) \ + (((x) & SSI_SFCSR_RFCNT1_MASK) >> SSI_SFCSR_RFCNT1_SHIFT) +#define SSI_SFCSR_TFCNT1_SHIFT 24 +#define SSI_SFCSR_TFCNT1_MASK 0x0F000000 +#define SSI_SFCSR_TFCNT1(x) \ + (((x) & SSI_SFCSR_TFCNT1_MASK) >> SSI_SFCSR_TFCNT1_SHIFT) +#define SSI_SFCSR_RFWM1_SHIFT 20 +#define SSI_SFCSR_RFWM1_MASK 0x00F00000 +#define SSI_SFCSR_RFWM1(x) \ + (((x) << SSI_SFCSR_RFWM1_SHIFT) & SSI_SFCSR_RFWM1_MASK) +#define SSI_SFCSR_TFWM1_SHIFT 16 +#define SSI_SFCSR_TFWM1_MASK 0x000F0000 +#define SSI_SFCSR_TFWM1(x) \ + (((x) << SSI_SFCSR_TFWM1_SHIFT) & SSI_SFCSR_TFWM1_MASK) +#define SSI_SFCSR_RFCNT0_SHIFT 12 +#define SSI_SFCSR_RFCNT0_MASK 0x0000F000 +#define SSI_SFCSR_RFCNT0(x) \ + (((x) & SSI_SFCSR_RFCNT0_MASK) >> SSI_SFCSR_RFCNT0_SHIFT) +#define SSI_SFCSR_TFCNT0_SHIFT 8 +#define SSI_SFCSR_TFCNT0_MASK 0x00000F00 +#define SSI_SFCSR_TFCNT0(x) \ + (((x) & SSI_SFCSR_TFCNT0_MASK) >> SSI_SFCSR_TFCNT0_SHIFT) +#define SSI_SFCSR_RFWM0_SHIFT 4 +#define SSI_SFCSR_RFWM0_MASK 0x000000F0 +#define SSI_SFCSR_RFWM0(x) \ + (((x) << SSI_SFCSR_RFWM0_SHIFT) & SSI_SFCSR_RFWM0_MASK) +#define SSI_SFCSR_TFWM0_SHIFT 0 +#define SSI_SFCSR_TFWM0_MASK 0x0000000F +#define SSI_SFCSR_TFWM0(x) \ + (((x) << SSI_SFCSR_TFWM0_SHIFT) & SSI_SFCSR_TFWM0_MASK) -/* SSI Test Register -- CCSR_SSI_STR 0x30 */ -#define CCSR_SSI_STR_TEST 0x00008000 -#define CCSR_SSI_STR_RCK2TCK 0x00004000 -#define CCSR_SSI_STR_RFS2TFS 0x00002000 -#define CCSR_SSI_STR_RXSTATE(x) (((x) >> 8) & 0x1F) -#define CCSR_SSI_STR_TXD2RXD 0x00000080 -#define CCSR_SSI_STR_TCK2RCK 0x00000040 -#define CCSR_SSI_STR_TFS2RFS 0x00000020 -#define CCSR_SSI_STR_TXSTATE(x) ((x) & 0x1F) +/* SSI Test Register -- REG_SSI_STR 0x30 */ +#define SSI_STR_TEST 0x00008000 +#define SSI_STR_RCK2TCK 0x00004000 +#define SSI_STR_RFS2TFS 0x00002000 +#define SSI_STR_RXSTATE(x) (((x) >> 8) & 0x1F) +#define SSI_STR_TXD2RXD 0x00000080 +#define SSI_STR_TCK2RCK 0x00000040 +#define SSI_STR_TFS2RFS 0x00000020 +#define SSI_STR_TXSTATE(x) ((x) & 0x1F) -/* SSI Option Register -- CCSR_SSI_SOR 0x34 */ -#define CCSR_SSI_SOR_CLKOFF 0x00000040 -#define CCSR_SSI_SOR_RX_CLR 0x00000020 -#define CCSR_SSI_SOR_TX_CLR 0x00000010 -#define CCSR_SSI_SOR_INIT 0x00000008 -#define CCSR_SSI_SOR_WAIT_SHIFT 1 -#define CCSR_SSI_SOR_WAIT_MASK 0x00000006 -#define CCSR_SSI_SOR_WAIT(x) (((x) & 3) << CCSR_SSI_SOR_WAIT_SHIFT) -#define CCSR_SSI_SOR_SYNRST 0x00000001 +/* SSI Option Register -- REG_SSI_SOR 0x34 */ +#define SSI_SOR_CLKOFF 0x00000040 +#define SSI_SOR_RX_CLR 0x00000020 +#define SSI_SOR_TX_CLR 0x00000010 +#define SSI_SOR_INIT 0x00000008 +#define SSI_SOR_WAIT_SHIFT 1 +#define SSI_SOR_WAIT_MASK 0x00000006 +#define SSI_SOR_WAIT(x) (((x) & 3) << SSI_SOR_WAIT_SHIFT) +#define SSI_SOR_SYNRST 0x00000001 -/* SSI AC97 Control Register -- CCSR_SSI_SACNT 0x38 */ -#define CCSR_SSI_SACNT_FRDIV(x) (((x) & 0x3f) << 5) -#define CCSR_SSI_SACNT_WR 0x00000010 -#define CCSR_SSI_SACNT_RD 0x00000008 -#define CCSR_SSI_SACNT_RDWR_MASK 0x00000018 -#define CCSR_SSI_SACNT_TIF 0x00000004 -#define CCSR_SSI_SACNT_FV 0x00000002 -#define CCSR_SSI_SACNT_AC97EN 0x00000001 +/* SSI AC97 Control Register -- REG_SSI_SACNT 0x38 */ +#define SSI_SACNT_FRDIV(x) (((x) & 0x3f) << 5) +#define SSI_SACNT_WR 0x00000010 +#define SSI_SACNT_RD 0x00000008 +#define SSI_SACNT_RDWR_MASK 0x00000018 +#define SSI_SACNT_TIF 0x00000004 +#define SSI_SACNT_FV 0x00000002 +#define SSI_SACNT_AC97EN 0x00000001 struct device; diff --git a/sound/soc/fsl/fsl_ssi_dbg.c b/sound/soc/fsl/fsl_ssi_dbg.c index 88d9e8e08905..362df91420f6 100644 --- a/sound/soc/fsl/fsl_ssi_dbg.c +++ b/sound/soc/fsl/fsl_ssi_dbg.c @@ -18,67 +18,67 @@ void fsl_ssi_dbg_isr(struct fsl_ssi_dbg *dbg, u32 sisr) { - if (sisr & CCSR_SSI_SISR_RFRC) + if (sisr & SSI_SISR_RFRC) dbg->stats.rfrc++; - if (sisr & CCSR_SSI_SISR_TFRC) + if (sisr & SSI_SISR_TFRC) dbg->stats.tfrc++; - if (sisr & CCSR_SSI_SISR_CMDAU) + if (sisr & SSI_SISR_CMDAU) dbg->stats.cmdau++; - if (sisr & CCSR_SSI_SISR_CMDDU) + if (sisr & SSI_SISR_CMDDU) dbg->stats.cmddu++; - if (sisr & CCSR_SSI_SISR_RXT) + if (sisr & SSI_SISR_RXT) dbg->stats.rxt++; - if (sisr & CCSR_SSI_SISR_RDR1) + if (sisr & SSI_SISR_RDR1) dbg->stats.rdr1++; - if (sisr & CCSR_SSI_SISR_RDR0) + if (sisr & SSI_SISR_RDR0) dbg->stats.rdr0++; - if (sisr & CCSR_SSI_SISR_TDE1) + if (sisr & SSI_SISR_TDE1) dbg->stats.tde1++; - if (sisr & CCSR_SSI_SISR_TDE0) + if (sisr & SSI_SISR_TDE0) dbg->stats.tde0++; - if (sisr & CCSR_SSI_SISR_ROE1) + if (sisr & SSI_SISR_ROE1) dbg->stats.roe1++; - if (sisr & CCSR_SSI_SISR_ROE0) + if (sisr & SSI_SISR_ROE0) dbg->stats.roe0++; - if (sisr & CCSR_SSI_SISR_TUE1) + if (sisr & SSI_SISR_TUE1) dbg->stats.tue1++; - if (sisr & CCSR_SSI_SISR_TUE0) + if (sisr & SSI_SISR_TUE0) dbg->stats.tue0++; - if (sisr & CCSR_SSI_SISR_TFS) + if (sisr & SSI_SISR_TFS) dbg->stats.tfs++; - if (sisr & CCSR_SSI_SISR_RFS) + if (sisr & SSI_SISR_RFS) dbg->stats.rfs++; - if (sisr & CCSR_SSI_SISR_TLS) + if (sisr & SSI_SISR_TLS) dbg->stats.tls++; - if (sisr & CCSR_SSI_SISR_RLS) + if (sisr & SSI_SISR_RLS) dbg->stats.rls++; - if (sisr & CCSR_SSI_SISR_RFF1) + if (sisr & SSI_SISR_RFF1) dbg->stats.rff1++; - if (sisr & CCSR_SSI_SISR_RFF0) + if (sisr & SSI_SISR_RFF0) dbg->stats.rff0++; - if (sisr & CCSR_SSI_SISR_TFE1) + if (sisr & SSI_SISR_TFE1) dbg->stats.tfe1++; - if (sisr & CCSR_SSI_SISR_TFE0) + if (sisr & SSI_SISR_TFE0) dbg->stats.tfe0++; } @@ -89,7 +89,7 @@ void fsl_ssi_dbg_isr(struct fsl_ssi_dbg *dbg, u32 sisr) */ #define SIER_SHOW(flag, name) \ do { \ - if (CCSR_SSI_SIER_##flag) \ + if (SSI_SIER_##flag) \ seq_printf(s, #name "=%u\n", ssi_dbg->stats.name); \ } while (0) -- cgit v1.2.3 From af4f7f388242d5e63e3026a03a12e18ef4d8f62c Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sun, 17 Dec 2017 18:52:04 -0800 Subject: ASoC: fsl_ssi: Refine indentations and wrappings This patch just simply unifies the coding style. Signed-off-by: Nicolin Chen Tested-by: Maciej S. Szmigiero Reviewed-by: Maciej S. Szmigiero Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 239 +++++++++++++++++++++----------------------- sound/soc/fsl/fsl_ssi.h | 2 +- sound/soc/fsl/fsl_ssi_dbg.c | 3 +- 3 files changed, 118 insertions(+), 126 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 24d96956b53a..ed9ac758e35d 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -69,21 +69,35 @@ * samples will be written to STX properly. */ #ifdef __BIG_ENDIAN -#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \ - SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_S20_3BE | \ - SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_S24_BE) +#define FSLSSI_I2S_FORMATS \ + (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_BE | \ + SNDRV_PCM_FMTBIT_S18_3BE | \ + SNDRV_PCM_FMTBIT_S20_3BE | \ + SNDRV_PCM_FMTBIT_S24_3BE | \ + SNDRV_PCM_FMTBIT_S24_BE) #else -#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \ - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) +#define FSLSSI_I2S_FORMATS \ + (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE) #endif -#define FSLSSI_SIER_DBG_RX_FLAGS (SSI_SIER_RFF0_EN | \ - SSI_SIER_RLS_EN | SSI_SIER_RFS_EN | \ - SSI_SIER_ROE0_EN | SSI_SIER_RFRC_EN) -#define FSLSSI_SIER_DBG_TX_FLAGS (SSI_SIER_TFE0_EN | \ - SSI_SIER_TLS_EN | SSI_SIER_TFS_EN | \ - SSI_SIER_TUE0_EN | SSI_SIER_TFRC_EN) +#define FSLSSI_SIER_DBG_RX_FLAGS \ + (SSI_SIER_RFF0_EN | \ + SSI_SIER_RLS_EN | \ + SSI_SIER_RFS_EN | \ + SSI_SIER_ROE0_EN | \ + SSI_SIER_RFRC_EN) +#define FSLSSI_SIER_DBG_TX_FLAGS \ + (SSI_SIER_TFE0_EN | \ + SSI_SIER_TLS_EN | \ + SSI_SIER_TFS_EN | \ + SSI_SIER_TUE0_EN | \ + SSI_SIER_TFRC_EN) enum fsl_ssi_type { FSL_SSI_MCP8610, @@ -291,8 +305,8 @@ static struct fsl_ssi_soc_data fsl_ssi_mpc8610 = { .imx = false, .offline_config = true, .sisr_write_mask = SSI_SISR_RFRC | SSI_SISR_TFRC | - SSI_SISR_ROE0 | SSI_SISR_ROE1 | - SSI_SISR_TUE0 | SSI_SISR_TUE1, + SSI_SISR_ROE0 | SSI_SISR_ROE1 | + SSI_SISR_TUE0 | SSI_SISR_TUE1, }; static struct fsl_ssi_soc_data fsl_ssi_imx21 = { @@ -306,15 +320,15 @@ static struct fsl_ssi_soc_data fsl_ssi_imx35 = { .imx = true, .offline_config = true, .sisr_write_mask = SSI_SISR_RFRC | SSI_SISR_TFRC | - SSI_SISR_ROE0 | SSI_SISR_ROE1 | - SSI_SISR_TUE0 | SSI_SISR_TUE1, + SSI_SISR_ROE0 | SSI_SISR_ROE1 | + SSI_SISR_TUE0 | SSI_SISR_TUE1, }; static struct fsl_ssi_soc_data fsl_ssi_imx51 = { .imx = true, .offline_config = false, .sisr_write_mask = SSI_SISR_ROE0 | SSI_SISR_ROE1 | - SSI_SISR_TUE0 | SSI_SISR_TUE1, + SSI_SISR_TUE0 | SSI_SISR_TUE1, }; static const struct of_device_id fsl_ssi_ids[] = { @@ -376,21 +390,21 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) if (enable) { regmap_update_bits(regs, REG_SSI_SIER, - vals->rx.sier | vals->tx.sier, - vals->rx.sier | vals->tx.sier); + vals->rx.sier | vals->tx.sier, + vals->rx.sier | vals->tx.sier); regmap_update_bits(regs, REG_SSI_SRCR, - vals->rx.srcr | vals->tx.srcr, - vals->rx.srcr | vals->tx.srcr); + vals->rx.srcr | vals->tx.srcr, + vals->rx.srcr | vals->tx.srcr); regmap_update_bits(regs, REG_SSI_STCR, - vals->rx.stcr | vals->tx.stcr, - vals->rx.stcr | vals->tx.stcr); + vals->rx.stcr | vals->tx.stcr, + vals->rx.stcr | vals->tx.stcr); } else { regmap_update_bits(regs, REG_SSI_SRCR, - vals->rx.srcr | vals->tx.srcr, 0); + vals->rx.srcr | vals->tx.srcr, 0); regmap_update_bits(regs, REG_SSI_STCR, - vals->rx.stcr | vals->tx.stcr, 0); + vals->rx.stcr | vals->tx.stcr, 0); regmap_update_bits(regs, REG_SSI_SIER, - vals->rx.sier | vals->tx.sier, 0); + vals->rx.sier | vals->tx.sier, 0); } } @@ -401,10 +415,10 @@ static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) { if (is_rx) { regmap_update_bits(ssi->regs, REG_SSI_SOR, - SSI_SOR_RX_CLR, SSI_SOR_RX_CLR); + SSI_SOR_RX_CLR, SSI_SOR_RX_CLR); } else { regmap_update_bits(ssi->regs, REG_SSI_SOR, - SSI_SOR_TX_CLR, SSI_SOR_TX_CLR); + SSI_SOR_TX_CLR, SSI_SOR_TX_CLR); } } @@ -432,7 +446,7 @@ static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) * Enable or disable SSI configuration. */ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, - struct fsl_ssi_reg_val *vals) + struct fsl_ssi_reg_val *vals) { struct regmap *regs = ssi->regs; struct fsl_ssi_reg_val *avals; @@ -442,8 +456,7 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, regmap_read(regs, REG_SSI_SCR, &scr_val); - nr_active_streams = !!(scr_val & SSI_SCR_TE) + - !!(scr_val & SSI_SCR_RE); + nr_active_streams = !!(scr_val & SSI_SCR_TE) + !!(scr_val & SSI_SCR_RE); if (nr_active_streams - 1 > 0) keep_active = 1; @@ -462,7 +475,7 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, * both streams, and get safe bits to disable current stream */ u32 scr = fsl_ssi_disable_val(vals->scr, avals->scr, - keep_active); + keep_active); /* Safely disable SCR register for the stream */ regmap_update_bits(regs, REG_SSI_SCR, scr, 0); } @@ -474,8 +487,7 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, * 2) Disable all remaining bits of both streams when last stream ends */ if (ssi->soc->offline_config) { - if ((enable && !nr_active_streams) || - (!enable && !keep_active)) + if ((enable && !nr_active_streams) || (!enable && !keep_active)) fsl_ssi_rxtx_config(ssi, enable); goto config_done; @@ -498,11 +510,11 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, * both streams, and get safe bits to disable current stream */ sier = fsl_ssi_disable_val(vals->sier, avals->sier, - keep_active); + keep_active); srcr = fsl_ssi_disable_val(vals->srcr, avals->srcr, - keep_active); + keep_active); stcr = fsl_ssi_disable_val(vals->stcr, avals->stcr, - keep_active); + keep_active); /* Safely disable other control registers for the stream */ regmap_update_bits(regs, REG_SSI_SRCR, srcr, 0); @@ -525,7 +537,7 @@ config_done: /* Enable SSI first to send TX DMA request */ regmap_update_bits(regs, REG_SSI_SCR, - SSI_SCR_SSIEN, SSI_SCR_SSIEN); + SSI_SCR_SSIEN, SSI_SCR_SSIEN); /* Busy wait until TX FIFO not empty -- DMA working */ for (i = 0; i < max_loop; i++) { @@ -544,7 +556,6 @@ config_done: } } - static void fsl_ssi_rx_config(struct fsl_ssi *ssi, bool enable) { fsl_ssi_config(ssi, enable, &ssi->rxtx_reg_val.rx); @@ -615,19 +626,16 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi *ssi) struct regmap *regs = ssi->regs; /* Setup the clock control register */ - regmap_write(regs, REG_SSI_STCCR, - SSI_SxCCR_WL(17) | SSI_SxCCR_DC(13)); - regmap_write(regs, REG_SSI_SRCCR, - SSI_SxCCR_WL(17) | SSI_SxCCR_DC(13)); + regmap_write(regs, REG_SSI_STCCR, SSI_SxCCR_WL(17) | SSI_SxCCR_DC(13)); + regmap_write(regs, REG_SSI_SRCCR, SSI_SxCCR_WL(17) | SSI_SxCCR_DC(13)); /* Enable AC97 mode and startup the SSI */ - regmap_write(regs, REG_SSI_SACNT, - SSI_SACNT_AC97EN | SSI_SACNT_FV); + regmap_write(regs, REG_SSI_SACNT, SSI_SACNT_AC97EN | SSI_SACNT_FV); /* AC97 has to communicate with codec before starting a stream */ regmap_update_bits(regs, REG_SSI_SCR, - SSI_SCR_SSIEN | SSI_SCR_TE | SSI_SCR_RE, - SSI_SCR_SSIEN | SSI_SCR_TE | SSI_SCR_RE); + SSI_SCR_SSIEN | SSI_SCR_TE | SSI_SCR_RE, + SSI_SCR_SSIEN | SSI_SCR_TE | SSI_SCR_RE); regmap_write(regs, REG_SSI_SOR, SSI_SOR_WAIT(3)); } @@ -651,19 +659,18 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, */ if (ssi->use_dual_fifo) snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2); + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2); return 0; } static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai); clk_disable_unprepare(ssi->clk); - } /** @@ -676,8 +683,8 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, * (In 2-channel I2S Master mode, slot_width is fixed 32) */ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai, - struct snd_pcm_hw_params *hw_params) + struct snd_soc_dai *cpu_dai, + struct snd_pcm_hw_params *hw_params) { struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); struct regmap *regs = ssi->regs; @@ -764,8 +771,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, stccr = SSI_SxCCR_PM(pm + 1) | (div2 ? SSI_SxCCR_DIV2 : 0) | (psr ? SSI_SxCCR_PSR : 0); - mask = SSI_SxCCR_PM_MASK | SSI_SxCCR_DIV2 | - SSI_SxCCR_PSR; + mask = SSI_SxCCR_PM_MASK | SSI_SxCCR_DIV2 | SSI_SxCCR_PSR; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || synchronous) regmap_update_bits(regs, REG_SSI_STCCR, mask, stccr); @@ -795,7 +801,8 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, * fsl_ssi_set_bclk() if SSI is the DAI clock master. */ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai) + struct snd_pcm_hw_params *hw_params, + struct snd_soc_dai *cpu_dai) { struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); struct regmap *regs = ssi->regs; @@ -837,36 +844,33 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, u8 i2smode; /* Normal + Network mode to send 16-bit data in 32-bit frames */ if (fsl_ssi_is_i2s_cbm_cfs(ssi) && sample_size == 16) - i2smode = SSI_SCR_I2S_MODE_NORMAL | - SSI_SCR_NET; + i2smode = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET; else i2smode = ssi->i2s_mode; regmap_update_bits(regs, REG_SSI_SCR, - SSI_SCR_NET | SSI_SCR_I2S_MODE_MASK, - channels == 1 ? 0 : i2smode); + SSI_SCR_NET | SSI_SCR_I2S_MODE_MASK, + channels == 1 ? 0 : i2smode); } /* In synchronous mode, the SSI uses STCCR for capture */ if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) || ssi->cpu_dai_drv.symmetric_rates) - regmap_update_bits(regs, REG_SSI_STCCR, SSI_SxCCR_WL_MASK, - wl); + regmap_update_bits(regs, REG_SSI_STCCR, SSI_SxCCR_WL_MASK, wl); else - regmap_update_bits(regs, REG_SSI_SRCCR, SSI_SxCCR_WL_MASK, - wl); + regmap_update_bits(regs, REG_SSI_SRCCR, SSI_SxCCR_WL_MASK, wl); return 0; } static int fsl_ssi_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) + struct snd_soc_dai *cpu_dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai); if (fsl_ssi_is_i2s_master(ssi) && - ssi->baudclk_streams & BIT(substream->stream)) { + ssi->baudclk_streams & BIT(substream->stream)) { clk_disable_unprepare(ssi->baudclk); ssi->baudclk_streams &= ~BIT(substream->stream); } @@ -896,8 +900,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, scr |= SSI_SCR_SYNC_TX_FS; mask = SSI_STCR_TXBIT0 | SSI_STCR_TFDIR | SSI_STCR_TXDIR | - SSI_STCR_TSCKP | SSI_STCR_TFSI | SSI_STCR_TFSL | - SSI_STCR_TEFS; + SSI_STCR_TSCKP | SSI_STCR_TFSI | SSI_STCR_TFSL | SSI_STCR_TEFS; regmap_read(regs, REG_SSI_STCR, &stcr); regmap_read(regs, REG_SSI_SRCR, &srcr); stcr &= ~mask; @@ -908,11 +911,9 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: regmap_update_bits(regs, REG_SSI_STCCR, - SSI_SxCCR_DC_MASK, - SSI_SxCCR_DC(2)); + SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(2)); regmap_update_bits(regs, REG_SSI_SRCCR, - SSI_SxCCR_DC_MASK, - SSI_SxCCR_DC(2)); + SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(2)); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFS: case SND_SOC_DAIFMT_CBS_CFS: @@ -927,7 +928,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, /* Data on rising edge of bclk, frame low, 1clk before data */ strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP | - SSI_STCR_TXBIT0 | SSI_STCR_TEFS; + SSI_STCR_TXBIT0 | SSI_STCR_TEFS; break; case SND_SOC_DAIFMT_LEFT_J: /* Data on rising edge of bclk, frame high */ @@ -936,12 +937,11 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, case SND_SOC_DAIFMT_DSP_A: /* Data on rising edge of bclk, frame high, 1clk before data */ strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP | - SSI_STCR_TXBIT0 | SSI_STCR_TEFS; + SSI_STCR_TXBIT0 | SSI_STCR_TEFS; break; case SND_SOC_DAIFMT_DSP_B: /* Data on rising edge of bclk, frame high */ - strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP | - SSI_STCR_TXBIT0; + strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP | SSI_STCR_TXBIT0; break; case SND_SOC_DAIFMT_AC97: /* Data on falling edge of bclk, frame high, 1clk before data */ @@ -1012,23 +1012,22 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, wm = ssi->fifo_watermark; regmap_write(regs, REG_SSI_SFCSR, - SSI_SFCSR_TFWM0(wm) | SSI_SFCSR_RFWM0(wm) | - SSI_SFCSR_TFWM1(wm) | SSI_SFCSR_RFWM1(wm)); + SSI_SFCSR_TFWM0(wm) | SSI_SFCSR_RFWM0(wm) | + SSI_SFCSR_TFWM1(wm) | SSI_SFCSR_RFWM1(wm)); if (ssi->use_dual_fifo) { - regmap_update_bits(regs, REG_SSI_SRCR, SSI_SRCR_RFEN1, - SSI_SRCR_RFEN1); - regmap_update_bits(regs, REG_SSI_STCR, SSI_STCR_TFEN1, - SSI_STCR_TFEN1); - regmap_update_bits(regs, REG_SSI_SCR, SSI_SCR_TCH_EN, - SSI_SCR_TCH_EN); + regmap_update_bits(regs, REG_SSI_SRCR, + SSI_SRCR_RFEN1, SSI_SRCR_RFEN1); + regmap_update_bits(regs, REG_SSI_STCR, + SSI_STCR_TFEN1, SSI_STCR_TFEN1); + regmap_update_bits(regs, REG_SSI_SCR, + SSI_SCR_TCH_EN, SSI_SCR_TCH_EN); } if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_AC97) fsl_ssi_setup_ac97(ssi); return 0; - } /** @@ -1049,7 +1048,7 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) * Set TDM slot number and slot width */ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, - u32 rx_mask, int slots, int slot_width) + u32 rx_mask, int slots, int slot_width) { struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); struct regmap *regs = ssi->regs; @@ -1069,17 +1068,16 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, return -EINVAL; } - regmap_update_bits(regs, REG_SSI_STCCR, SSI_SxCCR_DC_MASK, - SSI_SxCCR_DC(slots)); - regmap_update_bits(regs, REG_SSI_SRCCR, SSI_SxCCR_DC_MASK, - SSI_SxCCR_DC(slots)); + regmap_update_bits(regs, REG_SSI_STCCR, + SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(slots)); + regmap_update_bits(regs, REG_SSI_SRCCR, + SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(slots)); /* Save SSIEN bit of the SCR register */ regmap_read(regs, REG_SSI_SCR, &val); val &= SSI_SCR_SSIEN; /* Temporarily enable SSI to allow SxMSKs to be configurable */ - regmap_update_bits(regs, REG_SSI_SCR, SSI_SCR_SSIEN, - SSI_SCR_SSIEN); + regmap_update_bits(regs, REG_SSI_SCR, SSI_SCR_SSIEN, SSI_SCR_SSIEN); regmap_write(regs, REG_SSI_STMSK, ~tx_mask); regmap_write(regs, REG_SSI_SRMSK, ~rx_mask); @@ -1153,13 +1151,13 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { - .startup = fsl_ssi_startup, - .shutdown = fsl_ssi_shutdown, - .hw_params = fsl_ssi_hw_params, - .hw_free = fsl_ssi_hw_free, - .set_fmt = fsl_ssi_set_dai_fmt, - .set_tdm_slot = fsl_ssi_set_dai_tdm_slot, - .trigger = fsl_ssi_trigger, + .startup = fsl_ssi_startup, + .shutdown = fsl_ssi_shutdown, + .hw_params = fsl_ssi_hw_params, + .hw_free = fsl_ssi_hw_free, + .set_fmt = fsl_ssi_set_dai_fmt, + .set_tdm_slot = fsl_ssi_set_dai_tdm_slot, + .trigger = fsl_ssi_trigger, }; static struct snd_soc_dai_driver fsl_ssi_dai_template = { @@ -1182,7 +1180,7 @@ static struct snd_soc_dai_driver fsl_ssi_dai_template = { }; static const struct snd_soc_component_driver fsl_ssi_component = { - .name = "fsl-ssi", + .name = "fsl-ssi", }; static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { @@ -1206,11 +1204,10 @@ static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { .ops = &fsl_ssi_dai_ops, }; - static struct fsl_ssi *fsl_ac97_data; static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, - unsigned short val) + unsigned short val) { struct regmap *regs = fsl_ac97_data->regs; unsigned int lreg; @@ -1235,8 +1232,8 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, lval = val << 4; regmap_write(regs, REG_SSI_SACDAT, lval); - regmap_update_bits(regs, REG_SSI_SACNT, SSI_SACNT_RDWR_MASK, - SSI_SACNT_WR); + regmap_update_bits(regs, REG_SSI_SACNT, + SSI_SACNT_RDWR_MASK, SSI_SACNT_WR); udelay(100); clk_disable_unprepare(fsl_ac97_data->clk); @@ -1246,10 +1243,9 @@ ret_unlock: } static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, - unsigned short reg) + unsigned short reg) { struct regmap *regs = fsl_ac97_data->regs; - unsigned short val = 0; u32 reg_val; unsigned int lreg; @@ -1259,15 +1255,14 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, ret = clk_prepare_enable(fsl_ac97_data->clk); if (ret) { - pr_err("ac97 read clk_prepare_enable failed: %d\n", - ret); + pr_err("ac97 read clk_prepare_enable failed: %d\n", ret); goto ret_unlock; } lreg = (reg & 0x7f) << 12; regmap_write(regs, REG_SSI_SACADD, lreg); - regmap_update_bits(regs, REG_SSI_SACNT, SSI_SACNT_RDWR_MASK, - SSI_SACNT_RD); + regmap_update_bits(regs, REG_SSI_SACNT, + SSI_SACNT_RDWR_MASK, SSI_SACNT_RD); udelay(100); @@ -1282,8 +1277,8 @@ ret_unlock: } static struct snd_ac97_bus_ops fsl_ssi_ac97_ops = { - .read = fsl_ssi_ac97_read, - .write = fsl_ssi_ac97_write, + .read = fsl_ssi_ac97_read, + .write = fsl_ssi_ac97_write, }; /** @@ -1298,7 +1293,7 @@ static void make_lowercase(char *s) } static int fsl_ssi_imx_probe(struct platform_device *pdev, - struct fsl_ssi *ssi, void __iomem *iomem) + struct fsl_ssi *ssi, void __iomem *iomem) { struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; @@ -1370,14 +1365,13 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, return 0; error_pcm: - if (!ssi->has_ipg_clk_name) clk_disable_unprepare(ssi->clk); + return ret; } -static void fsl_ssi_imx_clean(struct platform_device *pdev, - struct fsl_ssi *ssi) +static void fsl_ssi_imx_clean(struct platform_device *pdev, struct fsl_ssi *ssi) { if (!ssi->use_dma) imx_pcm_fiq_exit(pdev); @@ -1422,8 +1416,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) if (fsl_ssi_is_ac97(ssi)) { memcpy(&ssi->cpu_dai_drv, &fsl_ssi_ac97_dai, - sizeof(fsl_ssi_ac97_dai)); - + sizeof(fsl_ssi_ac97_dai)); fsl_ac97_data = ssi; } else { memcpy(&ssi->cpu_dai_drv, &fsl_ssi_dai_template, @@ -1582,8 +1575,8 @@ done: goto error_sound_card; } - ssi->pdev = platform_device_register_data(NULL, - "ac97-codec", ssi_idx, NULL, 0); + ssi->pdev = platform_device_register_data(NULL, "ac97-codec", + ssi_idx, NULL, 0); if (IS_ERR(ssi->pdev)) { ret = PTR_ERR(ssi->pdev); dev_err(dev, @@ -1597,11 +1590,9 @@ done: error_sound_card: fsl_ssi_debugfs_remove(&ssi->dbg_stats); - error_asoc_register: if (fsl_ssi_is_ac97(ssi)) snd_soc_set_ac97_ops(NULL); - error_ac97_ops: if (fsl_ssi_is_ac97(ssi)) mutex_destroy(&ssi->ac97_reg_lock); @@ -1655,9 +1646,9 @@ static int fsl_ssi_resume(struct device *dev) regcache_cache_only(regs, false); regmap_update_bits(regs, REG_SSI_SFCSR, - SSI_SFCSR_RFWM1_MASK | SSI_SFCSR_TFWM1_MASK | - SSI_SFCSR_RFWM0_MASK | SSI_SFCSR_TFWM0_MASK, - ssi->regcache_sfcsr); + SSI_SFCSR_RFWM1_MASK | SSI_SFCSR_TFWM1_MASK | + SSI_SFCSR_RFWM0_MASK | SSI_SFCSR_TFWM0_MASK, + ssi->regcache_sfcsr); regmap_write(regs, REG_SSI_SACNT, ssi->regcache_sacnt); return regcache_sync(regs); diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h index cdcf3d23873e..fe38e6913f96 100644 --- a/sound/soc/fsl/fsl_ssi.h +++ b/sound/soc/fsl/fsl_ssi.h @@ -310,7 +310,7 @@ static inline void fsl_ssi_dbg_isr(struct fsl_ssi_dbg *stats, u32 sisr) } static inline int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, - struct device *dev) + struct device *dev) { return 0; } diff --git a/sound/soc/fsl/fsl_ssi_dbg.c b/sound/soc/fsl/fsl_ssi_dbg.c index 362df91420f6..7aac63e2c561 100644 --- a/sound/soc/fsl/fsl_ssi_dbg.c +++ b/sound/soc/fsl/fsl_ssi_dbg.c @@ -147,7 +147,8 @@ int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev) return -ENOMEM; ssi_dbg->dbg_stats = debugfs_create_file("stats", S_IRUGO, - ssi_dbg->dbg_dir, ssi_dbg, &fsl_ssi_stats_ops); + ssi_dbg->dbg_dir, ssi_dbg, + &fsl_ssi_stats_ops); if (!ssi_dbg->dbg_stats) { debugfs_remove(ssi_dbg->dbg_dir); return -ENOMEM; -- cgit v1.2.3 From 2c22503667709ced35fc6807c9ba79285c929114 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sun, 17 Dec 2017 18:52:05 -0800 Subject: ASoC: fsl_ssi: Refine printk outputs This patches unifies the error message in the "failed to xxxx" format. It also reduces the length of one line and adds spaces to an operator. Signed-off-by: Nicolin Chen Tested-by: Maciej S. Szmigiero Reviewed-by: Maciej S. Szmigiero Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index ed9ac758e35d..eb9ac847bda3 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -716,7 +716,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, * never greater than 1/5 IPG clock rate */ if (freq * 5 > clk_get_rate(ssi->clk)) { - dev_err(cpu_dai->dev, "bitclk > ipgclk/5\n"); + dev_err(cpu_dai->dev, "bitclk > ipgclk / 5\n"); return -EINVAL; } @@ -888,7 +888,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, ssi->dai_fmt = fmt; if (fsl_ssi_is_i2s_master(ssi) && IS_ERR(ssi->baudclk)) { - dev_err(dev, "baudclk is missing which is necessary for master mode\n"); + dev_err(dev, "missing baudclk for master mode\n"); return -EINVAL; } @@ -1307,7 +1307,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, ssi->clk = devm_clk_get(dev, NULL); if (IS_ERR(ssi->clk)) { ret = PTR_ERR(ssi->clk); - dev_err(dev, "could not get clock: %d\n", ret); + dev_err(dev, "failed to get clock: %d\n", ret); return ret; } @@ -1323,7 +1323,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, /* Do not error out for slave cases that live without a baud clock */ ssi->baudclk = devm_clk_get(dev, "baud"); if (IS_ERR(ssi->baudclk)) - dev_dbg(dev, "could not get baud clock: %ld\n", + dev_dbg(dev, "failed to get baud clock: %ld\n", PTR_ERR(ssi->baudclk)); ssi->dma_params_tx.maxburst = ssi->dma_maxburst; @@ -1447,7 +1447,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) ®config); } if (IS_ERR(ssi->regs)) { - dev_err(dev, "Failed to init register map\n"); + dev_err(dev, "failed to init register map\n"); return PTR_ERR(ssi->regs); } @@ -1513,7 +1513,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) mutex_init(&ssi->ac97_reg_lock); ret = snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev); if (ret) { - dev_err(dev, "could not set AC'97 ops\n"); + dev_err(dev, "failed to set AC'97 ops\n"); goto error_ac97_ops; } } @@ -1529,7 +1529,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) ret = devm_request_irq(dev, ssi->irq, fsl_ssi_isr, 0, dev_name(dev), ssi); if (ret < 0) { - dev_err(dev, "could not claim irq %u\n", ssi->irq); + dev_err(dev, "failed to claim irq %u\n", ssi->irq); goto error_asoc_register; } } @@ -1571,7 +1571,7 @@ done: ret = of_property_read_u32(np, "cell-index", &ssi_idx); if (ret) { - dev_err(dev, "cannot get SSI index property\n"); + dev_err(dev, "failed to get SSI index property\n"); goto error_sound_card; } -- cgit v1.2.3 From 0c884bed6ba743b8456c6eee4d599aaad6ffa008 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sun, 17 Dec 2017 18:52:06 -0800 Subject: ASoC: fsl_ssi: Rename cpu_dai parameter to dai Shortens the variable name to save space, useful for dev_err outputs. Signed-off-by: Nicolin Chen Tested-by: Maciej S. Szmigiero Reviewed-by: Maciej S. Szmigiero Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index eb9ac847bda3..237302fb9279 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -683,10 +683,10 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, * (In 2-channel I2S Master mode, slot_width is fixed 32) */ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai, + struct snd_soc_dai *dai, struct snd_pcm_hw_params *hw_params) { - struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; int synchronous = ssi->cpu_dai_drv.symmetric_rates, ret; u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i; @@ -716,7 +716,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, * never greater than 1/5 IPG clock rate */ if (freq * 5 > clk_get_rate(ssi->clk)) { - dev_err(cpu_dai->dev, "bitclk > ipgclk / 5\n"); + dev_err(dai->dev, "bitclk > ipgclk / 5\n"); return -EINVAL; } @@ -765,7 +765,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, /* No proper pm found if it is still remaining the initial value */ if (pm == 999) { - dev_err(cpu_dai->dev, "failed to handle the required sysclk\n"); + dev_err(dai->dev, "failed to handle the required sysclk\n"); return -EINVAL; } @@ -781,7 +781,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, if (!baudclk_is_used) { ret = clk_set_rate(ssi->baudclk, baudrate); if (ret) { - dev_err(cpu_dai->dev, "failed to set baudclk rate\n"); + dev_err(dai->dev, "failed to set baudclk rate\n"); return -EINVAL; } } @@ -802,9 +802,9 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, */ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, - struct snd_soc_dai *cpu_dai) + struct snd_soc_dai *dai) { - struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; unsigned int channels = params_channels(hw_params); unsigned int sample_size = params_width(hw_params); @@ -826,7 +826,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, return 0; if (fsl_ssi_is_i2s_master(ssi)) { - ret = fsl_ssi_set_bclk(substream, cpu_dai, hw_params); + ret = fsl_ssi_set_bclk(substream, dai, hw_params); if (ret) return ret; @@ -864,7 +864,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, } static int fsl_ssi_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai); @@ -1033,30 +1033,30 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, /** * Configure Digital Audio Interface (DAI) Format */ -static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) +static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); /* AC97 configured DAIFMT earlier in the probe() */ if (fsl_ssi_is_ac97(ssi)) return 0; - return _fsl_ssi_set_dai_fmt(cpu_dai->dev, ssi, fmt); + return _fsl_ssi_set_dai_fmt(dai->dev, ssi, fmt); } /** * Set TDM slot number and slot width */ -static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, +static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mask, int slots, int slot_width) { - struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); + struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; u32 val; /* The word length should be 8, 10, 12, 16, 18, 20, 22 or 24 */ if (slot_width & 1 || slot_width < 8 || slot_width > 24) { - dev_err(cpu_dai->dev, "invalid slot width: %d\n", slot_width); + dev_err(dai->dev, "invalid slot width: %d\n", slot_width); return -EINVAL; } @@ -1064,7 +1064,7 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, regmap_read(regs, REG_SSI_SCR, &val); val &= SSI_SCR_I2S_MODE_MASK | SSI_SCR_NET; if (val && slots < 2) { - dev_err(cpu_dai->dev, "slot number should be >= 2 in I2S or NET\n"); + dev_err(dai->dev, "slot number should be >= 2 in I2S or NET\n"); return -EINVAL; } -- cgit v1.2.3 From ff4adb090066c1636a43b88a497c34d2bd2312ec Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sun, 17 Dec 2017 18:52:07 -0800 Subject: ASoC: fsl_ssi: Rename scr_val to scr Simplify the variable name. This reduces one over-80-character line. Signed-off-by: Nicolin Chen Tested-by: Maciej S. Szmigiero Reviewed-by: Maciej S. Szmigiero Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 237302fb9279..af3ba718d4bb 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -451,12 +451,12 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, struct regmap *regs = ssi->regs; struct fsl_ssi_reg_val *avals; int nr_active_streams; - u32 scr_val; + u32 scr; int keep_active; - regmap_read(regs, REG_SSI_SCR, &scr_val); + regmap_read(regs, REG_SSI_SCR, &scr); - nr_active_streams = !!(scr_val & SSI_SCR_TE) + !!(scr_val & SSI_SCR_RE); + nr_active_streams = !!(scr & SSI_SCR_TE) + !!(scr & SSI_SCR_RE); if (nr_active_streams - 1 > 0) keep_active = 1; @@ -810,11 +810,11 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, unsigned int sample_size = params_width(hw_params); u32 wl = SSI_SxCCR_WL(sample_size); int ret; - u32 scr_val; + u32 scr; int enabled; - regmap_read(regs, REG_SSI_SCR, &scr_val); - enabled = scr_val & SSI_SCR_SSIEN; + regmap_read(regs, REG_SSI_SCR, &scr); + enabled = scr & SSI_SCR_SSIEN; /* * SSI is properly configured if it is enabled and running in -- cgit v1.2.3 From 2474e4037c4e3fe8b4fe4ab37232973d9b17a573 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sun, 17 Dec 2017 18:52:08 -0800 Subject: ASoC: fsl_ssi: Replace fsl_ssi_rxtx_reg_val with fsl_ssi_regvals The name fsl_ssi_rxtx_reg_val is too long to read comfortably. So this patch shortens it by using an array (fsl_ssi_regvals, renamed from fsl_ssi_reg_val). To do that, it also introduces two macros (TX and RX) to replace the wrapper structure. This will also help further cleanups. Meanwhile, it unifies all local variable with the name "vals" to get rid of the name "reg" -- could be confusing with "regs" in the private struct for regmap. Signed-off-by: Nicolin Chen Tested-by: Maciej S. Szmigiero Reviewed-by: Maciej S. Szmigiero Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 79 +++++++++++++++++++++++-------------------------- sound/soc/fsl/fsl_ssi.h | 3 ++ 2 files changed, 40 insertions(+), 42 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index af3ba718d4bb..aef014c46d96 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -106,18 +106,13 @@ enum fsl_ssi_type { FSL_SSI_MX51, }; -struct fsl_ssi_reg_val { +struct fsl_ssi_regvals { u32 sier; u32 srcr; u32 stcr; u32 scr; }; -struct fsl_ssi_rxtx_reg_val { - struct fsl_ssi_reg_val rx; - struct fsl_ssi_reg_val tx; -}; - static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -213,7 +208,7 @@ struct fsl_ssi_soc_data { * @fifo_depth: Depth of the SSI FIFOs * @slot_width: Width of each DAI slot * @slots: Number of slots - * @rxtx_reg_val: Specific RX/TX register settings + * @regvals: Specific RX/TX register settings * * @clk: Clock source to access register * @baudclk: Clock source to generate bit and frame-sync clocks @@ -257,7 +252,7 @@ struct fsl_ssi { unsigned int fifo_depth; unsigned int slot_width; unsigned int slots; - struct fsl_ssi_rxtx_reg_val rxtx_reg_val; + struct fsl_ssi_regvals regvals[2]; struct clk *clk; struct clk *baudclk; @@ -386,25 +381,25 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) { struct regmap *regs = ssi->regs; - struct fsl_ssi_rxtx_reg_val *vals = &ssi->rxtx_reg_val; + struct fsl_ssi_regvals *vals = ssi->regvals; if (enable) { regmap_update_bits(regs, REG_SSI_SIER, - vals->rx.sier | vals->tx.sier, - vals->rx.sier | vals->tx.sier); + vals[RX].sier | vals[TX].sier, + vals[RX].sier | vals[TX].sier); regmap_update_bits(regs, REG_SSI_SRCR, - vals->rx.srcr | vals->tx.srcr, - vals->rx.srcr | vals->tx.srcr); + vals[RX].srcr | vals[TX].srcr, + vals[RX].srcr | vals[TX].srcr); regmap_update_bits(regs, REG_SSI_STCR, - vals->rx.stcr | vals->tx.stcr, - vals->rx.stcr | vals->tx.stcr); + vals[RX].stcr | vals[TX].stcr, + vals[RX].stcr | vals[TX].stcr); } else { regmap_update_bits(regs, REG_SSI_SRCR, - vals->rx.srcr | vals->tx.srcr, 0); + vals[RX].srcr | vals[TX].srcr, 0); regmap_update_bits(regs, REG_SSI_STCR, - vals->rx.stcr | vals->tx.stcr, 0); + vals[RX].stcr | vals[TX].stcr, 0); regmap_update_bits(regs, REG_SSI_SIER, - vals->rx.sier | vals->tx.sier, 0); + vals[RX].sier | vals[TX].sier, 0); } } @@ -446,10 +441,10 @@ static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) * Enable or disable SSI configuration. */ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, - struct fsl_ssi_reg_val *vals) + struct fsl_ssi_regvals *vals) { struct regmap *regs = ssi->regs; - struct fsl_ssi_reg_val *avals; + struct fsl_ssi_regvals *avals; int nr_active_streams; u32 scr; int keep_active; @@ -464,10 +459,10 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, keep_active = 0; /* Get the opposite direction to keep its values untouched */ - if (&ssi->rxtx_reg_val.rx == vals) - avals = &ssi->rxtx_reg_val.tx; + if (&ssi->regvals[RX] == vals) + avals = &ssi->regvals[TX]; else - avals = &ssi->rxtx_reg_val.rx; + avals = &ssi->regvals[RX]; if (!enable) { /* @@ -558,7 +553,7 @@ config_done: static void fsl_ssi_rx_config(struct fsl_ssi *ssi, bool enable) { - fsl_ssi_config(ssi, enable, &ssi->rxtx_reg_val.rx); + fsl_ssi_config(ssi, enable, &ssi->regvals[RX]); } static void fsl_ssi_tx_ac97_saccst_setup(struct fsl_ssi *ssi) @@ -586,39 +581,39 @@ static void fsl_ssi_tx_config(struct fsl_ssi *ssi, bool enable) if (enable && fsl_ssi_is_ac97(ssi)) fsl_ssi_tx_ac97_saccst_setup(ssi); - fsl_ssi_config(ssi, enable, &ssi->rxtx_reg_val.tx); + fsl_ssi_config(ssi, enable, &ssi->regvals[TX]); } /** * Cache critical bits of SIER, SRCR, STCR and SCR to later set them safely */ -static void fsl_ssi_setup_reg_vals(struct fsl_ssi *ssi) +static void fsl_ssi_setup_regvals(struct fsl_ssi *ssi) { - struct fsl_ssi_rxtx_reg_val *reg = &ssi->rxtx_reg_val; + struct fsl_ssi_regvals *vals = ssi->regvals; - reg->rx.sier = SSI_SIER_RFF0_EN; - reg->rx.srcr = SSI_SRCR_RFEN0; - reg->rx.scr = 0; - reg->tx.sier = SSI_SIER_TFE0_EN; - reg->tx.stcr = SSI_STCR_TFEN0; - reg->tx.scr = 0; + vals[RX].sier = SSI_SIER_RFF0_EN; + vals[RX].srcr = SSI_SRCR_RFEN0; + vals[RX].scr = 0; + vals[TX].sier = SSI_SIER_TFE0_EN; + vals[TX].stcr = SSI_STCR_TFEN0; + vals[TX].scr = 0; /* AC97 has already enabled SSIEN, RE and TE, so ignore them */ if (!fsl_ssi_is_ac97(ssi)) { - reg->rx.scr = SSI_SCR_SSIEN | SSI_SCR_RE; - reg->tx.scr = SSI_SCR_SSIEN | SSI_SCR_TE; + vals[RX].scr = SSI_SCR_SSIEN | SSI_SCR_RE; + vals[TX].scr = SSI_SCR_SSIEN | SSI_SCR_TE; } if (ssi->use_dma) { - reg->rx.sier |= SSI_SIER_RDMAE; - reg->tx.sier |= SSI_SIER_TDMAE; + vals[RX].sier |= SSI_SIER_RDMAE; + vals[TX].sier |= SSI_SIER_TDMAE; } else { - reg->rx.sier |= SSI_SIER_RIE; - reg->tx.sier |= SSI_SIER_TIE; + vals[RX].sier |= SSI_SIER_RIE; + vals[TX].sier |= SSI_SIER_TIE; } - reg->rx.sier |= FSLSSI_SIER_DBG_RX_FLAGS; - reg->tx.sier |= FSLSSI_SIER_DBG_TX_FLAGS; + vals[RX].sier |= FSLSSI_SIER_DBG_RX_FLAGS; + vals[TX].sier |= FSLSSI_SIER_DBG_TX_FLAGS; } static void fsl_ssi_setup_ac97(struct fsl_ssi *ssi) @@ -892,7 +887,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, return -EINVAL; } - fsl_ssi_setup_reg_vals(ssi); + fsl_ssi_setup_regvals(ssi); regmap_read(regs, REG_SSI_SCR, &scr); scr &= ~(SSI_SCR_SYN | SSI_SCR_I2S_MODE_MASK); diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h index fe38e6913f96..52b88f1d6c6f 100644 --- a/sound/soc/fsl/fsl_ssi.h +++ b/sound/soc/fsl/fsl_ssi.h @@ -12,6 +12,9 @@ #ifndef _MPC8610_I2S_H #define _MPC8610_I2S_H +#define RX 0 +#define TX 1 + /* -- SSI Register Map -- */ /* SSI Transmit Data Register 0 */ -- cgit v1.2.3 From 8bc84a3344ca27836cff29bfbb42365753c9c557 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sun, 17 Dec 2017 18:52:09 -0800 Subject: ASoC: fsl_ssi: Rename i2smode to i2s_net Since this i2smode also includes the setting of Network mode, it should have it in the name. This patch also adds its MASK define. Signed-off-by: Nicolin Chen Tested-by: Maciej S. Szmigiero Reviewed-by: Maciej S. Szmigiero Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 24 ++++++++++++------------ sound/soc/fsl/fsl_ssi.h | 1 + 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index aef014c46d96..2b3915c45199 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -201,7 +201,7 @@ struct fsl_ssi_soc_data { * @cpu_dai_drv: CPU DAI driver for this device * * @dai_fmt: DAI configuration this device is currently used with - * @i2s_mode: I2S and Network mode configuration of SCR register + * @i2s_net: I2S and Network mode configurations of SCR register * @use_dma: DMA is used or FIQ with stream filter * @use_dual_fifo: DMA with support for dual FIFO mode * @has_ipg_clk_name: If "ipg" is in the clock name list of device tree @@ -245,7 +245,7 @@ struct fsl_ssi { struct snd_soc_dai_driver cpu_dai_drv; unsigned int dai_fmt; - u8 i2s_mode; + u8 i2s_net; bool use_dma; bool use_dual_fifo; bool has_ipg_clk_name; @@ -836,16 +836,16 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, } if (!fsl_ssi_is_ac97(ssi)) { - u8 i2smode; + u8 i2s_net; /* Normal + Network mode to send 16-bit data in 32-bit frames */ if (fsl_ssi_is_i2s_cbm_cfs(ssi) && sample_size == 16) - i2smode = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET; + i2s_net = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET; else - i2smode = ssi->i2s_mode; + i2s_net = ssi->i2s_net; regmap_update_bits(regs, REG_SSI_SCR, - SSI_SCR_NET | SSI_SCR_I2S_MODE_MASK, - channels == 1 ? 0 : i2smode); + SSI_SCR_I2S_NET_MASK, + channels == 1 ? 0 : i2s_net); } /* In synchronous mode, the SSI uses STCCR for capture */ @@ -902,7 +902,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, srcr &= ~mask; /* Use Network mode as default */ - ssi->i2s_mode = SSI_SCR_NET; + ssi->i2s_net = SSI_SCR_NET; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: regmap_update_bits(regs, REG_SSI_STCCR, @@ -912,10 +912,10 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFS: case SND_SOC_DAIFMT_CBS_CFS: - ssi->i2s_mode |= SSI_SCR_I2S_MODE_MASTER; + ssi->i2s_net |= SSI_SCR_I2S_MODE_MASTER; break; case SND_SOC_DAIFMT_CBM_CFM: - ssi->i2s_mode |= SSI_SCR_I2S_MODE_SLAVE; + ssi->i2s_net |= SSI_SCR_I2S_MODE_SLAVE; break; default: return -EINVAL; @@ -940,12 +940,12 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, break; case SND_SOC_DAIFMT_AC97: /* Data on falling edge of bclk, frame high, 1clk before data */ - ssi->i2s_mode |= SSI_SCR_I2S_MODE_NORMAL; + ssi->i2s_net |= SSI_SCR_I2S_MODE_NORMAL; break; default: return -EINVAL; } - scr |= ssi->i2s_mode; + scr |= ssi->i2s_net; /* DAI clock inversion */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h index 52b88f1d6c6f..b61008779e3c 100644 --- a/sound/soc/fsl/fsl_ssi.h +++ b/sound/soc/fsl/fsl_ssi.h @@ -95,6 +95,7 @@ #define SSI_SCR_I2S_MODE_SLAVE 0x00000040 #define SSI_SCR_SYN 0x00000010 #define SSI_SCR_NET 0x00000008 +#define SSI_SCR_I2S_NET_MASK (SSI_SCR_NET | SSI_SCR_I2S_MODE_MASK) #define SSI_SCR_RE 0x00000004 #define SSI_SCR_TE 0x00000002 #define SSI_SCR_SSIEN 0x00000001 -- cgit v1.2.3 From 52eee84e815e0fbaf9ada848ab5646314a529b61 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sun, 17 Dec 2017 18:52:10 -0800 Subject: ASoC: fsl_ssi: Define ternary macros to simplify code Some regmap code looks redudant. So simplify it. Signed-off-by: Nicolin Chen Tested-by: Maciej S. Szmigiero Reviewed-by: Maciej S. Szmigiero Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 27 +++++++++++---------------- sound/soc/fsl/fsl_ssi.h | 4 ++++ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 2b3915c45199..aecd00f7929d 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -408,13 +408,10 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) */ static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) { - if (is_rx) { - regmap_update_bits(ssi->regs, REG_SSI_SOR, - SSI_SOR_RX_CLR, SSI_SOR_RX_CLR); - } else { - regmap_update_bits(ssi->regs, REG_SSI_SOR, - SSI_SOR_TX_CLR, SSI_SOR_TX_CLR); - } + bool tx = !is_rx; + + regmap_update_bits(ssi->regs, REG_SSI_SOR, + SSI_SOR_xX_CLR(tx), SSI_SOR_xX_CLR(tx)); } /** @@ -681,6 +678,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, struct snd_pcm_hw_params *hw_params) { + bool tx2, tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; int synchronous = ssi->cpu_dai_drv.symmetric_rates, ret; @@ -768,10 +766,9 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, (psr ? SSI_SxCCR_PSR : 0); mask = SSI_SxCCR_PM_MASK | SSI_SxCCR_DIV2 | SSI_SxCCR_PSR; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || synchronous) - regmap_update_bits(regs, REG_SSI_STCCR, mask, stccr); - else - regmap_update_bits(regs, REG_SSI_SRCCR, mask, stccr); + /* STCCR is used for RX in synchronous mode */ + tx2 = tx || synchronous; + regmap_update_bits(regs, REG_SSI_SxCCR(tx2), mask, stccr); if (!baudclk_is_used) { ret = clk_set_rate(ssi->baudclk, baudrate); @@ -799,6 +796,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) { + bool tx2, tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; unsigned int channels = params_channels(hw_params); @@ -849,11 +847,8 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, } /* In synchronous mode, the SSI uses STCCR for capture */ - if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) || - ssi->cpu_dai_drv.symmetric_rates) - regmap_update_bits(regs, REG_SSI_STCCR, SSI_SxCCR_WL_MASK, wl); - else - regmap_update_bits(regs, REG_SSI_SRCCR, SSI_SxCCR_WL_MASK, wl); + tx2 = tx || ssi->cpu_dai_drv.symmetric_rates; + regmap_update_bits(regs, REG_SSI_SxCCR(tx2), SSI_SxCCR_WL_MASK, wl); return 0; } diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h index b61008779e3c..de2fdc5db726 100644 --- a/sound/soc/fsl/fsl_ssi.h +++ b/sound/soc/fsl/fsl_ssi.h @@ -35,10 +35,12 @@ #define REG_SSI_STCR 0x1c /* SSI Receive Configuration Register */ #define REG_SSI_SRCR 0x20 +#define REG_SSI_SxCR(tx) ((tx) ? REG_SSI_STCR : REG_SSI_SRCR) /* SSI Transmit Clock Control Register */ #define REG_SSI_STCCR 0x24 /* SSI Receive Clock Control Register */ #define REG_SSI_SRCCR 0x28 +#define REG_SSI_SxCCR(tx) ((tx) ? REG_SSI_STCCR : REG_SSI_SRCCR) /* SSI FIFO Control/Status Register */ #define REG_SSI_SFCSR 0x2c /* @@ -67,6 +69,7 @@ #define REG_SSI_STMSK 0x48 /* SSI Receive Time Slot Mask Register */ #define REG_SSI_SRMSK 0x4c +#define REG_SSI_SxMSK(tx) ((tx) ? REG_SSI_STMSK : REG_SSI_SRMSK) /* * SSI AC97 Channel Status Register * @@ -249,6 +252,7 @@ #define SSI_SOR_CLKOFF 0x00000040 #define SSI_SOR_RX_CLR 0x00000020 #define SSI_SOR_TX_CLR 0x00000010 +#define SSI_SOR_xX_CLR(tx) ((tx) ? SSI_SOR_TX_CLR : SSI_SOR_RX_CLR) #define SSI_SOR_INIT 0x00000008 #define SSI_SOR_WAIT_SHIFT 1 #define SSI_SOR_WAIT_MASK 0x00000006 -- cgit v1.2.3 From 2f8aab3d29fda158fa49ecae94b3b3a4b494909d Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 27 Nov 2017 20:03:14 +0800 Subject: ASoC: rl6231: get better PLL parameters For those which can only get approximation PLL out cases, this patch will use higher resolution to get a better PLL parameter. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rl6231.c | 95 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 29 deletions(-) diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c index 974a9040651d..33690e98e297 100644 --- a/sound/soc/codecs/rl6231.c +++ b/sound/soc/codecs/rl6231.c @@ -13,6 +13,7 @@ #include #include +#include #include "rl6231.h" /** @@ -106,6 +107,25 @@ static const struct pll_calc_map pll_preset_table[] = { {19200000, 24576000, 3, 30, 3, false}, }; +static unsigned int find_best_div(unsigned int in, + unsigned int max, unsigned int div) +{ + unsigned int d; + + if (in <= max) + return 1; + + d = in / max; + if (in % max) + d++; + + while (div % d != 0) + d++; + + + return d; +} + /** * rl6231_pll_calc - Calcualte PLL M/N/K code. * @freq_in: external clock provided to codec. @@ -120,9 +140,11 @@ int rl6231_pll_calc(const unsigned int freq_in, const unsigned int freq_out, struct rl6231_pll_code *pll_code) { int max_n = RL6231_PLL_N_MAX, max_m = RL6231_PLL_M_MAX; - int i, k, red, n_t, pll_out, in_t, out_t; - int n = 0, m = 0, m_t = 0; - int red_t = abs(freq_out - freq_in); + int i, k, n_t; + int k_t, min_k, max_k, n = 0, m = 0, m_t = 0; + unsigned int red, pll_out, in_t, out_t, div, div_t; + unsigned int red_t = abs(freq_out - freq_in); + unsigned int f_in, f_out, f_max; bool bypass = false; if (RL6231_PLL_INP_MAX < freq_in || RL6231_PLL_INP_MIN > freq_in) @@ -140,39 +162,54 @@ int rl6231_pll_calc(const unsigned int freq_in, } } - k = 100000000 / freq_out - 2; - if (k > RL6231_PLL_K_MAX) - k = RL6231_PLL_K_MAX; - for (n_t = 0; n_t <= max_n; n_t++) { - in_t = freq_in / (k + 2); - pll_out = freq_out / (n_t + 2); - if (in_t < 0) - continue; - if (in_t == pll_out) { - bypass = true; - n = n_t; - goto code_find; - } - red = abs(in_t - pll_out); - if (red < red_t) { - bypass = true; - n = n_t; - m = m_t; - if (red == 0) + min_k = 80000000 / freq_out - 2; + max_k = 150000000 / freq_out - 2; + if (max_k > RL6231_PLL_K_MAX) + max_k = RL6231_PLL_K_MAX; + if (min_k > RL6231_PLL_K_MAX) + min_k = max_k = RL6231_PLL_K_MAX; + div_t = gcd(freq_in, freq_out); + f_max = 0xffffffff / RL6231_PLL_N_MAX; + div = find_best_div(freq_in, f_max, div_t); + f_in = freq_in / div; + f_out = freq_out / div; + k = min_k; + for (k_t = min_k; k_t <= max_k; k_t++) { + for (n_t = 0; n_t <= max_n; n_t++) { + in_t = f_in * (n_t + 2); + pll_out = f_out * (k_t + 2); + if (in_t < 0) + continue; + if (in_t == pll_out) { + bypass = true; + n = n_t; + k = k_t; goto code_find; - red_t = red; - } - for (m_t = 0; m_t <= max_m; m_t++) { - out_t = in_t / (m_t + 2); - red = abs(out_t - pll_out); + } + out_t = in_t / (k_t + 2); + red = abs(f_out - out_t); if (red < red_t) { - bypass = false; + bypass = true; n = n_t; - m = m_t; + m = 0; + k = k_t; if (red == 0) goto code_find; red_t = red; } + for (m_t = 0; m_t <= max_m; m_t++) { + out_t = in_t / ((m_t + 2) * (k_t + 2)); + red = abs(f_out - out_t); + if (red < red_t) { + bypass = false; + n = n_t; + m = m_t; + k = k_t; + if (red == 0) + goto code_find; + red_t = red; + } + } } } pr_debug("Only get approximation about PLL\n"); -- cgit v1.2.3 From 56a23ee52611ca76421f3d7cac100e1616716dae Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 19 Dec 2017 13:38:23 +0100 Subject: ALSA: usb-audio: Proper fallback at get_term_name() get_term_name() calls snd_usb_copy_string_desc() for retrieving the name when a specific ID (name field) is given. When this returns an error (zero), however, it simply returns as is. This will end up in a fixed name string in the caller side, which often is meaningless. For giving a bit more useful name string depending on the terminal type, change the get_term_name() function to go through the fallback mode. Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 2b4ceda36291..9afb8ab524c7 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -656,10 +656,14 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm unsigned char *name, int maxlen, int term_only) { struct iterm_name_combo *names; + int len; - if (iterm->name) - return snd_usb_copy_string_desc(state, iterm->name, + if (iterm->name) { + len = snd_usb_copy_string_desc(state, iterm->name, name, maxlen); + if (len) + return len; + } /* virtual type - not a real terminal */ if (iterm->type >> 16) { -- cgit v1.2.3 From 8e9d8e19b3d0c36d45161233eee3f2d368efe3ac Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Mon, 18 Dec 2017 10:46:49 +0530 Subject: ASoC: Intel: Skylake: Request IRQ late only after all context are initialized Sometimes during boot, panic is observed at sst_dsp_shim_read_unlocked(). This happens when interrupt occurs before the context is initialized. So move the irq initialization only after the context is initialized completely. Signed-off-by: Subhransu S. Prusty Signed-off-by: Pawse, GuruprasadX Signed-off-by: Guneshwor Singh Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/bxt-sst.c | 2 +- sound/soc/intel/skylake/cnl-sst.c | 2 +- sound/soc/intel/skylake/skl-sst-dsp.c | 14 ++++++++++---- sound/soc/intel/skylake/skl-sst-dsp.h | 1 + sound/soc/intel/skylake/skl-sst.c | 2 +- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 4524211960e4..440bca7afbf1 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -595,7 +595,7 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3); skl->d0i3.state = SKL_DSP_D0I3_NONE; - return 0; + return skl_dsp_acquire_irq(sst); } EXPORT_SYMBOL_GPL(bxt_sst_dsp_init); diff --git a/sound/soc/intel/skylake/cnl-sst.c b/sound/soc/intel/skylake/cnl-sst.c index 387de388ce29..245df1067ba8 100644 --- a/sound/soc/intel/skylake/cnl-sst.c +++ b/sound/soc/intel/skylake/cnl-sst.c @@ -458,7 +458,7 @@ int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, cnl->boot_complete = false; init_waitqueue_head(&cnl->boot_wait); - return 0; + return skl_dsp_acquire_irq(sst); } EXPORT_SYMBOL_GPL(cnl_sst_dsp_init); diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c index 19ee1d4f3bdf..71e31ad0bb3f 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ b/sound/soc/intel/skylake/skl-sst-dsp.c @@ -435,16 +435,22 @@ struct sst_dsp *skl_dsp_ctx_init(struct device *dev, return NULL; } + return sst; +} + +int skl_dsp_acquire_irq(struct sst_dsp *sst) +{ + struct sst_dsp_device *sst_dev = sst->sst_dev; + int ret; + /* Register the ISR */ ret = request_threaded_irq(sst->irq, sst->ops->irq_handler, sst_dev->thread, IRQF_SHARED, "AudioDSP", sst); - if (ret) { + if (ret) dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n", sst->irq); - return NULL; - } - return sst; + return ret; } void skl_dsp_free(struct sst_dsp *dsp) diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index b8e799ed65ef..12fc9a73dc8a 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -206,6 +206,7 @@ int skl_cldma_wait_interruptible(struct sst_dsp *ctx); void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); struct sst_dsp *skl_dsp_ctx_init(struct device *dev, struct sst_dsp_device *sst_dev, int irq); +int skl_dsp_acquire_irq(struct sst_dsp *sst); bool is_skl_dsp_running(struct sst_dsp *ctx); unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx); diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index a436abf2fe3f..5a7e41b65ef3 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -569,7 +569,7 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, sst->fw_ops = skl_fw_ops; - return 0; + return skl_dsp_acquire_irq(sst); } EXPORT_SYMBOL_GPL(skl_sst_dsp_init); -- cgit v1.2.3 From 752c93aa72e60ba573bbcfcd508b9cc550db0b94 Mon Sep 17 00:00:00 2001 From: Pankaj Bharadiya Date: Mon, 18 Dec 2017 10:46:50 +0530 Subject: ASoC: Intel: Skylake: Ensure dai and dailink registration happens in sequence. Platform registration happens in probe work handler whereas machine device is registered during skl_probe. This sometimes results in cpu dais not found if the work handler is sufficiently delayed due to system load, even with deferred probe of machine driver. So move machine device registration after registering platform. Signed-off-by: Pankaj Bharadiya Signed-off-by: Subhransu S. Prusty Signed-off-by: Guneshwor Singh Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 56 +++++++++++++++++++++++++++++-------------- sound/soc/intel/skylake/skl.h | 1 + 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index a89592b2850e..32ce64c6b2dc 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -453,19 +453,34 @@ static struct skl_ssp_clk skl_ssp_clks[] = { {.name = "ssp5_sclkfs"}, }; -static int skl_machine_device_register(struct skl *skl, void *driver_data) +static int skl_find_machine(struct skl *skl, void *driver_data) { - struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); - struct platform_device *pdev; struct snd_soc_acpi_mach *mach = driver_data; - int ret; + struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); + struct skl_machine_pdata *pdata; mach = snd_soc_acpi_find_machine(mach); if (mach == NULL) { dev_err(bus->dev, "No matching machine driver found\n"); return -ENODEV; } + + skl->mach = mach; skl->fw_name = mach->fw_filename; + pdata = skl->mach->pdata; + + if (mach->pdata) + skl->use_tplg_pcm = pdata->use_tplg_pcm; + + return 0; +} + +static int skl_machine_device_register(struct skl *skl) +{ + struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); + struct snd_soc_acpi_mach *mach = skl->mach; + struct platform_device *pdev; + int ret; pdev = platform_device_alloc(mach->drv_name, -1); if (pdev == NULL) { @@ -480,11 +495,8 @@ static int skl_machine_device_register(struct skl *skl, void *driver_data) return -EIO; } - if (mach->pdata) { - skl->use_tplg_pcm = - ((struct skl_machine_pdata *)mach->pdata)->use_tplg_pcm; + if (mach->pdata) dev_set_drvdata(&pdev->dev, mach->pdata); - } skl->i2s_dev = pdev; @@ -701,18 +713,30 @@ static void skl_probe_work(struct work_struct *work) /* create codec instances */ skl_codec_create(ebus); + /* register platform dai and controls */ + err = skl_platform_register(bus->dev); + if (err < 0) { + dev_err(bus->dev, "platform register failed: %d\n", err); + return; + } + + if (bus->ppcap) { + err = skl_machine_device_register(skl); + if (err < 0) { + dev_err(bus->dev, "machine register failed: %d\n", err); + goto out_err; + } + } + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { err = snd_hdac_display_power(bus, false); if (err < 0) { dev_err(bus->dev, "Cannot turn off display power on i915\n"); + skl_machine_device_unregister(skl); return; } } - /* register platform dai and controls */ - err = skl_platform_register(bus->dev); - if (err < 0) - return; /* * we are done probing so decrement link counts */ @@ -882,18 +906,16 @@ static int skl_probe(struct pci_dev *pci, if (err < 0) goto out_clk_free; - err = skl_machine_device_register(skl, - (void *)pci_id->driver_data); + err = skl_find_machine(skl, (void *)pci_id->driver_data); if (err < 0) goto out_nhlt_free; err = skl_init_dsp(skl); if (err < 0) { dev_dbg(bus->dev, "error failed to register dsp\n"); - goto out_mach_free; + goto out_nhlt_free; } skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; - } if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(ebus); @@ -911,8 +933,6 @@ static int skl_probe(struct pci_dev *pci, out_dsp_free: skl_free_dsp(skl); -out_mach_free: - skl_machine_device_unregister(skl); out_clk_free: skl_clock_device_unregister(skl); out_nhlt_free: diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 46dda88ba139..f411579bc713 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -94,6 +94,7 @@ struct skl { struct skl_module **modules; bool use_tplg_pcm; struct skl_fw_config cfg; + struct snd_soc_acpi_mach *mach; }; #define skl_to_ebus(s) (&(s)->ebus) -- cgit v1.2.3 From 1e02dac395fadfff1f2c6bd90f1180f64a9cbebe Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 20 Dec 2017 01:48:13 +0000 Subject: ASoC: hdac_hdmi: keep DAI driver pointer in private data struct snd_soc_component::dai_drv will be removed soon. hdac_hdmi is only user of it. Let's keep it on private data. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 68a4a6b4e68e..15c3638fe345 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -136,6 +136,7 @@ struct hdac_hdmi_priv { struct mutex pin_mutex; struct hdac_chmap chmap; struct hdac_hdmi_drv_data *drv_data; + struct snd_soc_dai_driver *dai_drv; }; #define hdev_to_hdmi_priv(_hdev) ((to_ehdac_device(_hdev))->private_data) @@ -1035,7 +1036,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) struct snd_soc_dapm_route *route; struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev); - struct snd_soc_dai_driver *dai_drv = dapm->component->dai_drv; + struct snd_soc_dai_driver *dai_drv = hdmi->dai_drv; char widget_name[NAME_SIZE]; struct hdac_hdmi_cvt *cvt; struct hdac_hdmi_pin *pin; @@ -1437,6 +1438,7 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdev, } *dais = hdmi_dais; + hdmi->dai_drv = hdmi_dais; return 0; } -- cgit v1.2.3 From 58bf4179000a37aa9b0ee9ab2796f7573c77fff0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 20 Dec 2017 01:48:29 +0000 Subject: ASoC: soc-core: remove dai_drv from snd_soc_component ALSA SoC has some duplicate parameter. snd_soc_component::dai_drv is one of them. Each DAI is keeping its driver as snd_soc_dai::driver, and component has dai_list. This means, we can reach to each DAI and its driver by using dai_link. Thus, there is no need to keep DAI driver pointer on component. Let's remove it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 1 - sound/soc/soc-core.c | 14 ++++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 1a7323238c49..871e1fabd701 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -858,7 +858,6 @@ struct snd_soc_component { struct list_head card_aux_list; /* for auxiliary bound components */ struct list_head card_list; - struct snd_soc_dai_driver *dai_drv; int num_dai; const struct snd_soc_component_driver *driver; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c0edac80df34..6a13fbcba23f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3149,7 +3149,7 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, if (!dai->driver->ops) dai->driver->ops = &null_dai_ops; - list_add(&dai->list, &component->dai_list); + list_add_tail(&dai->list, &component->dai_list); component->num_dai++; dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); @@ -3176,8 +3176,6 @@ static int snd_soc_register_dais(struct snd_soc_component *component, dev_dbg(dev, "ASoC: dai register %s #%zu\n", dev_name(dev), count); - component->dai_drv = dai_drv; - for (i = 0; i < count; i++) { dai = soc_add_dai(component, dai_drv + i, @@ -4354,6 +4352,7 @@ int snd_soc_get_dai_name(struct of_phandle_args *args, args, dai_name); } else { + struct snd_soc_dai *dai; int id = -1; switch (args->args_count) { @@ -4375,7 +4374,14 @@ int snd_soc_get_dai_name(struct of_phandle_args *args, ret = 0; - *dai_name = pos->dai_drv[id].name; + /* find target DAI */ + list_for_each_entry(dai, &pos->dai_list, list) { + if (id == 0) + break; + id--; + } + + *dai_name = dai->driver->name; if (!*dai_name) *dai_name = pos->name; } -- cgit v1.2.3 From 4855f6a6283fc8ea1f79c9f49c91940afef64ef6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 20 Dec 2017 01:48:44 +0000 Subject: ASoC: soc.h: Arrange DAI related parameter "dai_list" and "num_dai" on snd_soc_component are related parameter. Let's arrange these. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 871e1fabd701..be6b462e2c01 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -858,11 +858,10 @@ struct snd_soc_component { struct list_head card_aux_list; /* for auxiliary bound components */ struct list_head card_list; - int num_dai; - const struct snd_soc_component_driver *driver; struct list_head dai_list; + int num_dai; int (*read)(struct snd_soc_component *, unsigned int, unsigned int *); int (*write)(struct snd_soc_component *, unsigned int, unsigned int); -- cgit v1.2.3 From 790dde243f7dd5b8e576686eba0b891470b09f57 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 21 Dec 2017 11:21:33 +0800 Subject: ASoC: rl6231: remove never matched if condition (in_t < 0) will never be true since in_t is unsigned. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rl6231.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c index 33690e98e297..7ef3b5476bcc 100644 --- a/sound/soc/codecs/rl6231.c +++ b/sound/soc/codecs/rl6231.c @@ -178,8 +178,6 @@ int rl6231_pll_calc(const unsigned int freq_in, for (n_t = 0; n_t <= max_n; n_t++) { in_t = f_in * (n_t + 2); pll_out = f_out * (k_t + 2); - if (in_t < 0) - continue; if (in_t == pll_out) { bypass = true; n = n_t; -- cgit v1.2.3 From 5fb6e0a1a933cfe13200ae0ae7589263236fa108 Mon Sep 17 00:00:00 2001 From: Guneshwor Singh Date: Thu, 21 Dec 2017 08:45:29 +0530 Subject: ASoC: hdac_hdmi: Add vendor id for Cannonlake HDMI codec Cannonlake HDMI codec has the same nid as Geminilake. This adds the vendor id for Cannonlake in hdmi device id list. Signed-off-by: Guneshwor Singh Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index f3b4f4dfae6a..69416f465d94 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2192,6 +2192,8 @@ static const struct hda_device_id hdmi_list[] = { HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0), HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0), + HDA_CODEC_EXT_ENTRY(0x8086280c, 0x100000, "Cannonlake HDMI", + &intel_glk_drv_data), HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", &intel_glk_drv_data), {} -- cgit v1.2.3 From ac769ab17282e4ca1b95fdc22c58975cba8f3619 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 20 Dec 2017 01:37:13 +0000 Subject: ASoC: wm2200: use snd_soc_codec_get_drvdata() snd_soc_codec_get_drvdata() is common function to get private data. Let's use it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index d83dab57a1d1..2d03db6efb79 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1550,7 +1550,7 @@ static const struct snd_soc_dapm_route wm2200_dapm_routes[] = { static int wm2200_probe(struct snd_soc_codec *codec) { - struct wm2200_priv *wm2200 = dev_get_drvdata(codec->dev); + struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec); int ret; wm2200->codec = codec; -- cgit v1.2.3 From 0e2d95aadd5c3bddfa4145b964527df12d89ec6a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 20 Dec 2017 01:37:54 +0000 Subject: ASoC: wm2200: don't use snd_soc_dai::symmetric_rates wm2200 is the only user of snd_soc_dai::symmetric_rates. Now, wm2200 is using single DAI on Component. Thus, wm2200_priv : snd_soc_dai : snd_soc_component are 1 : 1 : 1. We can replace snd_soc_dai::symmetric_rates on wm2200_priv. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 2d03db6efb79..5c2f5727244d 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -98,6 +98,8 @@ struct wm2200_priv { int rev; int sysclk; + + unsigned int symmetric_rates:1; }; #define WM2200_DSP_RANGE_BASE (WM2200_MAX_REGISTER + 1) @@ -1758,7 +1760,7 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream, lrclk = bclk_rates[bclk] / params_rate(params); dev_dbg(codec->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || - dai->symmetric_rates) + wm2200->symmetric_rates) snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_7, WM2200_AIF1RX_BCPF_MASK, lrclk); else @@ -2059,13 +2061,14 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source, static int wm2200_dai_probe(struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; + struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec); unsigned int val = 0; int ret; ret = snd_soc_read(codec, WM2200_GPIO_CTRL_1); if (ret >= 0) { if ((ret & WM2200_GP1_FN_MASK) != 0) { - dai->symmetric_rates = true; + wm2200->symmetric_rates = true; val = WM2200_AIF1TX_LRCLK_SRC; } } else { -- cgit v1.2.3 From 574d31d013d977be1cfe909da6c227c950856822 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 20 Dec 2017 01:38:26 +0000 Subject: ASoC: soc-dai.h: remove symmetric_xxx from snd_soc_dai ALSA SoC has some duplicate parameter. snd_soc_dai::symmetric_xxx are one of them. commit f0fba2ad1b6b ("ASoC: multi-component - ASoC Multi-Component Support") moved "symmetric_xxx" flags from snd_soc_dai to snd_soc_dai_driver. No one is using snd_soc_dai::symmetric_xxx now. Let's remove it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 58acd00cae19..e05d05b5a790 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -294,9 +294,6 @@ struct snd_soc_dai { /* DAI runtime info */ unsigned int capture_active:1; /* stream is in use */ unsigned int playback_active:1; /* stream is in use */ - unsigned int symmetric_rates:1; - unsigned int symmetric_channels:1; - unsigned int symmetric_samplebits:1; unsigned int probed:1; unsigned int active; -- cgit v1.2.3 From c1350bff69d13369c3316f5d5e580021c2196f90 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 27 Dec 2017 09:03:45 +0100 Subject: ALSA: hda - Clean up ALC299 init code ALC299 is compatible with ALC225/295, thus it doesn't have to assign its own model. Merge together with ALC225/295 code. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8fd2d9c62c96..b2037131eed9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6923,12 +6923,9 @@ static int patch_alc269(struct hda_codec *codec) break; case 0x10ec0225: case 0x10ec0295: - spec->codec_variant = ALC269_TYPE_ALC225; - spec->gen.mixer_nid = 0; /* no loopback on ALC225 ALC295 */ - break; case 0x10ec0299: spec->codec_variant = ALC269_TYPE_ALC225; - spec->gen.mixer_nid = 0; /* no loopback on ALC299 */ + spec->gen.mixer_nid = 0; /* no loopback on ALC225, ALC295 and ALC299 */ break; case 0x10ec0234: case 0x10ec0274: -- cgit v1.2.3 From 7a0a87160a1dc09220ec485b31d0f82f687a053f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 2 Jan 2018 11:00:57 +0100 Subject: ALSA: pcm: Set config update bits only when really changed The PCM config space refine codes touch the parameter rmask and cmask bits when the given config parameter is changed. But in most places it checks only whether the changed value is non-zero or not, and they don't consider whether a negative error value is returned. This will lead to the incorrect update bits set upon the error path. Fix the codes to check properly the return code whether it's really updated or an error. Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_oss.c | 10 +++++----- sound/core/pcm_lib.c | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index e49f448ee04f..5d131088ac7c 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -186,7 +186,7 @@ static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params, { int changed; changed = snd_mask_refine(hw_param_mask(params, var), val); - if (changed) { + if (changed > 0) { params->cmask |= 1 << var; params->rmask |= 1 << var; } @@ -233,7 +233,7 @@ static int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params, val, open); else return -EINVAL; - if (changed) { + if (changed > 0) { params->cmask |= 1 << var; params->rmask |= 1 << var; } @@ -294,7 +294,7 @@ static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params, val, open); else return -EINVAL; - if (changed) { + if (changed > 0) { params->cmask |= 1 << var; params->rmask |= 1 << var; } @@ -500,7 +500,7 @@ static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params, } } else return -EINVAL; - if (changed) { + if (changed > 0) { params->cmask |= 1 << var; params->rmask |= 1 << var; } @@ -540,7 +540,7 @@ static int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params, { int changed; changed = snd_interval_setinteger(hw_param_interval(params, var)); - if (changed) { + if (changed > 0) { params->cmask |= 1 << var; params->rmask |= 1 << var; } diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 10e7ef7a8804..bfff8d001466 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1603,7 +1603,7 @@ static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, changed = snd_interval_refine_first(hw_param_interval(params, var)); else return -EINVAL; - if (changed) { + if (changed > 0) { params->cmask |= 1 << var; params->rmask |= 1 << var; } @@ -1649,7 +1649,7 @@ static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, changed = snd_interval_refine_last(hw_param_interval(params, var)); else return -EINVAL; - if (changed) { + if (changed > 0) { params->cmask |= 1 << var; params->rmask |= 1 << var; } -- cgit v1.2.3 From 2dc6e1a4883a3eba451c76b726c23a580ed05307 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 2 Jan 2018 19:53:11 +0100 Subject: ASoC: rt5645: set in2_diff flag for GPD win and pocket devices The GPD pocket has a differential signal microphone and needs in2_diff to be set to avoid getting a very noisy signal. Since the GPD pocket and win use the same DMI strings, they share their platform data-definition, so enabling in2_diff on the pocket also sets it on the GPD win. The GPD win has a normal microphone, but setting in2_diff there does not negatively impact the sound from the microphone. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index a1a7bb770745..6dd894c9f355 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3628,6 +3628,8 @@ static const struct rt5645_platform_data gpd_win_platform_data = { .jd_mode = 3, .inv_jd1_1 = true, .long_name = "gpd-win-pocket-rt5645", + /* The GPD pocket has a diff. mic, for the win this does not matter. */ + .in2_diff = true, }; static const struct dmi_system_id dmi_platform_gpd_win[] = { -- cgit v1.2.3 From 78f5605c0329f8b108a915a46032093628f6054b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 2 Jan 2018 19:53:12 +0100 Subject: ASoC: rt5645: cleanup DMI matching code Rather then doing a dmi_check_system() per possible system use an array with all known systems, with dmi_system_id.driver_data pointing to the platform-data for the matching system. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 124 +++++++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 73 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 6dd894c9f355..df6cd5bd6a9f 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3573,66 +3573,74 @@ static const struct acpi_device_id rt5645_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match); #endif -static const struct rt5645_platform_data general_platform_data = { +static const struct rt5645_platform_data intel_braswell_platform_data = { .dmic1_data_pin = RT5645_DMIC1_DISABLE, .dmic2_data_pin = RT5645_DMIC_DATA_IN2P, .jd_mode = 3, }; -static const struct dmi_system_id dmi_platform_intel_braswell[] = { +static const struct rt5645_platform_data buddy_platform_data = { + .dmic1_data_pin = RT5645_DMIC_DATA_GPIO5, + .dmic2_data_pin = RT5645_DMIC_DATA_IN2P, + .jd_mode = 3, + .level_trigger_irq = true, +}; + +static const struct rt5645_platform_data gpd_win_platform_data = { + .jd_mode = 3, + .inv_jd1_1 = true, + .long_name = "gpd-win-pocket-rt5645", + /* The GPD pocket has a diff. mic, for the win this does not matter. */ + .in2_diff = true, +}; + +static const struct rt5645_platform_data asus_t100ha_platform_data = { + .dmic1_data_pin = RT5645_DMIC_DATA_IN2N, + .dmic2_data_pin = RT5645_DMIC2_DISABLE, + .jd_mode = 3, + .inv_jd1_1 = true, +}; + +static const struct rt5645_platform_data jd_mode3_platform_data = { + .jd_mode = 3, +}; + +static const struct dmi_system_id dmi_platform_data[] = { + { + .ident = "Chrome Buddy", + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Buddy"), + }, + .driver_data = (void *)&buddy_platform_data, + }, { .ident = "Intel Strago", .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "Strago"), }, + .driver_data = (void *)&intel_braswell_platform_data, }, { .ident = "Google Chrome", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), }, + .driver_data = (void *)&intel_braswell_platform_data, }, { .ident = "Google Setzer", .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "Setzer"), }, + .driver_data = (void *)&intel_braswell_platform_data, }, { .ident = "Microsoft Surface 3", .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), }, + .driver_data = (void *)&intel_braswell_platform_data, }, - { } -}; - -static const struct rt5645_platform_data buddy_platform_data = { - .dmic1_data_pin = RT5645_DMIC_DATA_GPIO5, - .dmic2_data_pin = RT5645_DMIC_DATA_IN2P, - .jd_mode = 3, - .level_trigger_irq = true, -}; - -static const struct dmi_system_id dmi_platform_intel_broadwell[] = { - { - .ident = "Chrome Buddy", - .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "Buddy"), - }, - }, - { } -}; - -static const struct rt5645_platform_data gpd_win_platform_data = { - .jd_mode = 3, - .inv_jd1_1 = true, - .long_name = "gpd-win-pocket-rt5645", - /* The GPD pocket has a diff. mic, for the win this does not matter. */ - .in2_diff = true, -}; - -static const struct dmi_system_id dmi_platform_gpd_win[] = { { /* * Match for the GPDwin which unfortunately uses somewhat @@ -3643,61 +3651,34 @@ static const struct dmi_system_id dmi_platform_gpd_win[] = { * the same default product_name. Also the GPDwin is the * only device to have both board_ and product_name not set. */ - .ident = "GPD Win", + .ident = "GPD Win / Pocket", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), DMI_MATCH(DMI_BOARD_NAME, "Default string"), DMI_MATCH(DMI_BOARD_SERIAL, "Default string"), DMI_MATCH(DMI_PRODUCT_NAME, "Default string"), }, + .driver_data = (void *)&gpd_win_platform_data, }, - {} -}; - -static const struct rt5645_platform_data general_platform_data2 = { - .dmic1_data_pin = RT5645_DMIC_DATA_IN2N, - .dmic2_data_pin = RT5645_DMIC2_DISABLE, - .jd_mode = 3, - .inv_jd1_1 = true, -}; - -static const struct dmi_system_id dmi_platform_asus_t100ha[] = { { .ident = "ASUS T100HAN", .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_PRODUCT_NAME, "T100HAN"), }, + .driver_data = (void *)&asus_t100ha_platform_data, }, - { } -}; - -static const struct rt5645_platform_data minix_z83_4_platform_data = { - .jd_mode = 3, -}; - -static const struct dmi_system_id dmi_platform_minix_z83_4[] = { { .ident = "MINIX Z83-4", .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MINIX"), DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"), }, + .driver_data = (void *)&jd_mode3_platform_data, }, { } }; -static bool rt5645_check_dp(struct device *dev) -{ - if (device_property_present(dev, "realtek,in2-differential") || - device_property_present(dev, "realtek,dmic1-data-pin") || - device_property_present(dev, "realtek,dmic2-data-pin") || - device_property_present(dev, "realtek,jd-mode")) - return true; - - return false; -} - static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev) { rt5645->pdata.in2_diff = device_property_read_bool(dev, @@ -3716,6 +3697,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct rt5645_platform_data *pdata = dev_get_platdata(&i2c->dev); + const struct dmi_system_id *dmi_data; struct rt5645_priv *rt5645; int ret, i; unsigned int val; @@ -3729,20 +3711,16 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, rt5645->i2c = i2c; i2c_set_clientdata(i2c, rt5645); + dmi_data = dmi_first_match(dmi_platform_data); + if (dmi_data) { + dev_info(&i2c->dev, "Detected %s platform\n", dmi_data->ident); + pdata = dmi_data->driver_data; + } + if (pdata) rt5645->pdata = *pdata; - else if (dmi_check_system(dmi_platform_intel_broadwell)) - rt5645->pdata = buddy_platform_data; - else if (rt5645_check_dp(&i2c->dev)) + else rt5645_parse_dt(rt5645, &i2c->dev); - else if (dmi_check_system(dmi_platform_intel_braswell)) - rt5645->pdata = general_platform_data; - else if (dmi_check_system(dmi_platform_gpd_win)) - rt5645->pdata = gpd_win_platform_data; - else if (dmi_check_system(dmi_platform_asus_t100ha)) - rt5645->pdata = general_platform_data2; - else if (dmi_check_system(dmi_platform_minix_z83_4)) - rt5645->pdata = minix_z83_4_platform_data; if (quirk != -1) { rt5645->pdata.in2_diff = QUIRK_IN2_DIFF(quirk); -- cgit v1.2.3 From a249a95667f4f814b9b15f4b59049ffe68b5677f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 2 Jan 2018 19:53:13 +0100 Subject: ASoC: rt5645: add platform data for the Teclast X80 Pro tablet The Teclast X80 Pro tablet needs jd_mode = 3 for headset jack detection. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index df6cd5bd6a9f..daf7b73ba415 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3676,6 +3676,14 @@ static const struct dmi_system_id dmi_platform_data[] = { }, .driver_data = (void *)&jd_mode3_platform_data, }, + { + .ident = "Teclast X80 Pro", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), + DMI_MATCH(DMI_PRODUCT_NAME, "X80 Pro"), + }, + .driver_data = (void *)&jd_mode3_platform_data, + }, { } }; -- cgit v1.2.3 From b70b309950418437bbd2a30afd169c4f09dee3e5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 2 Jan 2018 19:53:14 +0100 Subject: ASoC: Intel: cht_bsw_rt5645: Analog Mic support Various Cherry Trail boards with a rt5645 codec have an analog mic connected to IN2P + IN2N. The mic on this boards also needs micbias to be enabled, on some boards micbias1 is used and on others micbias2, so we enable both. This commit adds a new "Int Analog Mic" DAPM widget for this, so that we do not end up enabling micbias on boards with a digital mic which uses the already present "Int Mic" widget. Some existing UCM files already refer to "Int Mic" for their "Internal Analog Microphones" SectionDevice, but these don't work anyways since they enable the RECMIX BST1 Switch instead of the BST2 switch. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5645.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 18d129caa974..f898ee140cdc 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -118,6 +118,7 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_MIC("Int Analog Mic", NULL), SND_SOC_DAPM_SPK("Ext Spk", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -128,6 +129,8 @@ static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = { {"IN1N", NULL, "Headset Mic"}, {"DMIC L1", NULL, "Int Mic"}, {"DMIC R1", NULL, "Int Mic"}, + {"IN2P", NULL, "Int Analog Mic"}, + {"IN2N", NULL, "Int Analog Mic"}, {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, {"Ext Spk", NULL, "SPOL"}, @@ -135,6 +138,9 @@ static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = { {"Headphone", NULL, "Platform Clock"}, {"Headset Mic", NULL, "Platform Clock"}, {"Int Mic", NULL, "Platform Clock"}, + {"Int Analog Mic", NULL, "Platform Clock"}, + {"Int Analog Mic", NULL, "micbias1"}, + {"Int Analog Mic", NULL, "micbias2"}, {"Ext Spk", NULL, "Platform Clock"}, }; @@ -189,6 +195,7 @@ static const struct snd_kcontrol_new cht_mc_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Int Analog Mic"), SOC_DAPM_PIN_SWITCH("Ext Spk"), }; -- cgit v1.2.3 From d5cc0a1fcbb5ddbef9fdd4c4a978da3254ddbf37 Mon Sep 17 00:00:00 2001 From: Pardha Saradhi K Date: Tue, 2 Jan 2018 14:59:57 +0530 Subject: ASoC: Intel: Skylake: Disable clock gating during firmware and library download During firmware and library download, sometimes it is observed that firmware and library download is timed-out resulting into probe failure. This patch disables dynamic clock gating while firmware and library download. Signed-off-by: Pardha Saradhi K Signed-off-by: Sanyog Kale Signed-off-by: Guneshwor Singh Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 4 ++++ sound/soc/intel/skylake/skl-pcm.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 4e63213a8d55..933c1fbb222f 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -417,7 +417,11 @@ int skl_resume_dsp(struct skl *skl) if (skl->skl_sst->is_first_boot == true) return 0; + /* disable dynamic clock gating during fw and lib download */ + ctx->enable_miscbdcge(ctx->dev, false); + ret = skl_dsp_wake(ctx->dsp); + ctx->enable_miscbdcge(ctx->dev, true); if (ret < 0) return ret; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index cc6535ab84d1..b45a9cd5f058 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1342,7 +1342,11 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform) return -EIO; } + /* disable dynamic clock gating during fw and lib download */ + skl->skl_sst->enable_miscbdcge(platform->dev, false); + ret = ops->init_fw(platform->dev, skl->skl_sst); + skl->skl_sst->enable_miscbdcge(platform->dev, true); if (ret < 0) { dev_err(platform->dev, "Failed to boot first fw: %d\n", ret); return ret; -- cgit v1.2.3 From dd6bb9b16f23f9b95b77713c45bd6182336c5b2e Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 2 Jan 2018 19:47:18 +0800 Subject: ASoC: mediatek: fix error handling in mt2701_afe_pcm_dev_probe() Fix unbalanced error handling path which will get incorrect counts if probe failed. The .remove() should be adjusted accordingly. Signed-off-by: Ryder Lee Tested-by: Garlic Tseng Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 31 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c index 8fda182f849b..a7362d1cda1b 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -1590,12 +1590,16 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, afe); - pm_runtime_enable(&pdev->dev); - if (!pm_runtime_enabled(&pdev->dev)) - goto err_pm_disable; - pm_runtime_get_sync(&pdev->dev); - ret = snd_soc_register_platform(&pdev->dev, &mtk_afe_pcm_platform); + pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) { + ret = mt2701_afe_runtime_resume(dev); + if (ret) + goto err_pm_disable; + } + pm_runtime_get_sync(dev); + + ret = snd_soc_register_platform(dev, &mtk_afe_pcm_platform); if (ret) { dev_warn(dev, "err_platform\n"); goto err_platform; @@ -1610,35 +1614,28 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) goto err_dai_component; } - mt2701_afe_runtime_resume(&pdev->dev); - return 0; err_dai_component: - snd_soc_unregister_component(&pdev->dev); - + snd_soc_unregister_platform(dev); err_platform: - snd_soc_unregister_platform(&pdev->dev); - + pm_runtime_put_sync(dev); err_pm_disable: - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); return ret; } static int mt2701_afe_pcm_dev_remove(struct platform_device *pdev) { - struct mtk_base_afe *afe = platform_get_drvdata(pdev); - + pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) mt2701_afe_runtime_suspend(&pdev->dev); - pm_runtime_put_sync(&pdev->dev); snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_platform(&pdev->dev); - /* disable afe clock */ - mt2701_afe_disable_clock(afe); + return 0; } -- cgit v1.2.3 From b9f902b7fd800214b5598a636ceb74bfe2db63be Mon Sep 17 00:00:00 2001 From: Banajit Goswami Date: Sun, 31 Dec 2017 20:40:14 -0800 Subject: ASoC: change mask in snd_soc_get/put_volsw_sx to unsigned int If the result of (min + max) is negative in functions snd_soc_get_volsw_sx() or snd_soc_put_volsw_sx(), there will be an overflow for the variable 'mask'. UBSAN: Undefined behaviour in sound/soc/soc-ops.c:382:6 signed integer overflow: -2147483648 - 1 cannot be represented in type 'int' Fix this by updating the variable type of 'mask' to unsigned int. Signed-off-by: Banajit Goswami Signed-off-by: Mark Brown --- sound/soc/soc-ops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index 500f98c730b9..7144a51ddfa9 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -378,7 +378,7 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, unsigned int rshift = mc->rshift; int max = mc->max; int min = mc->min; - int mask = (1 << (fls(min + max) - 1)) - 1; + unsigned int mask = (1 << (fls(min + max) - 1)) - 1; unsigned int val; int ret; @@ -423,7 +423,7 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, unsigned int rshift = mc->rshift; int max = mc->max; int min = mc->min; - int mask = (1 << (fls(min + max) - 1)) - 1; + unsigned int mask = (1 << (fls(min + max) - 1)) - 1; int err = 0; unsigned int val, val_mask, val2 = 0; -- cgit v1.2.3 From d8d99d8ed658a705909b07ba21b643c53851d70c Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 2 Jan 2018 19:47:19 +0800 Subject: ASoC: mediatek: rework clock functions for MT2701 Reworks clock part to make it more reasonable. The current changes are: - Replace regmap operations by CCF APIs. Doing so, we just need to handle the element clocks and can also get accurate information via CCF. - Rename clocks to make them more generic so that the future revisions of the IP can adapt gracefully. - Regroup 'aud_clks[]' by usage - the basic needs and I2S parts: The new code just keep the common clocks in array and let SoC self decide I2S numbers - If future chips have different sets of channels we will add a little more abstract here. Moreover, this patch moves I2S clocks to the struct mt2701_i2s_data so that we can easily manage them when calls .prepare() and .shutdown(). Signed-off-by: Ryder Lee Tested-by: Garlic Tseng Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c | 518 +++++++--------------- sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h | 15 +- sound/soc/mediatek/mt2701/mt2701-afe-common.h | 64 +-- sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 45 +- 4 files changed, 200 insertions(+), 442 deletions(-) diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c index affa7fb25dd9..75ccdca5811d 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c @@ -21,442 +21,256 @@ #include "mt2701-afe-common.h" #include "mt2701-afe-clock-ctrl.h" -static const char *aud_clks[MT2701_CLOCK_NUM] = { - [MT2701_AUD_INFRA_SYS_AUDIO] = "infra_sys_audio_clk", - [MT2701_AUD_AUD_MUX1_SEL] = "top_audio_mux1_sel", - [MT2701_AUD_AUD_MUX2_SEL] = "top_audio_mux2_sel", - [MT2701_AUD_AUD_MUX1_DIV] = "top_audio_mux1_div", - [MT2701_AUD_AUD_MUX2_DIV] = "top_audio_mux2_div", - [MT2701_AUD_AUD_48K_TIMING] = "top_audio_48k_timing", - [MT2701_AUD_AUD_44K_TIMING] = "top_audio_44k_timing", - [MT2701_AUD_AUDPLL_MUX_SEL] = "top_audpll_mux_sel", - [MT2701_AUD_APLL_SEL] = "top_apll_sel", - [MT2701_AUD_AUD1PLL_98M] = "top_aud1_pll_98M", - [MT2701_AUD_AUD2PLL_90M] = "top_aud2_pll_90M", - [MT2701_AUD_HADDS2PLL_98M] = "top_hadds2_pll_98M", - [MT2701_AUD_HADDS2PLL_294M] = "top_hadds2_pll_294M", - [MT2701_AUD_AUDPLL] = "top_audpll", - [MT2701_AUD_AUDPLL_D4] = "top_audpll_d4", - [MT2701_AUD_AUDPLL_D8] = "top_audpll_d8", - [MT2701_AUD_AUDPLL_D16] = "top_audpll_d16", - [MT2701_AUD_AUDPLL_D24] = "top_audpll_d24", - [MT2701_AUD_AUDINTBUS] = "top_audintbus_sel", - [MT2701_AUD_CLK_26M] = "clk_26m", - [MT2701_AUD_SYSPLL1_D4] = "top_syspll1_d4", - [MT2701_AUD_AUD_K1_SRC_SEL] = "top_aud_k1_src_sel", - [MT2701_AUD_AUD_K2_SRC_SEL] = "top_aud_k2_src_sel", - [MT2701_AUD_AUD_K3_SRC_SEL] = "top_aud_k3_src_sel", - [MT2701_AUD_AUD_K4_SRC_SEL] = "top_aud_k4_src_sel", - [MT2701_AUD_AUD_K5_SRC_SEL] = "top_aud_k5_src_sel", - [MT2701_AUD_AUD_K6_SRC_SEL] = "top_aud_k6_src_sel", - [MT2701_AUD_AUD_K1_SRC_DIV] = "top_aud_k1_src_div", - [MT2701_AUD_AUD_K2_SRC_DIV] = "top_aud_k2_src_div", - [MT2701_AUD_AUD_K3_SRC_DIV] = "top_aud_k3_src_div", - [MT2701_AUD_AUD_K4_SRC_DIV] = "top_aud_k4_src_div", - [MT2701_AUD_AUD_K5_SRC_DIV] = "top_aud_k5_src_div", - [MT2701_AUD_AUD_K6_SRC_DIV] = "top_aud_k6_src_div", - [MT2701_AUD_AUD_I2S1_MCLK] = "top_aud_i2s1_mclk", - [MT2701_AUD_AUD_I2S2_MCLK] = "top_aud_i2s2_mclk", - [MT2701_AUD_AUD_I2S3_MCLK] = "top_aud_i2s3_mclk", - [MT2701_AUD_AUD_I2S4_MCLK] = "top_aud_i2s4_mclk", - [MT2701_AUD_AUD_I2S5_MCLK] = "top_aud_i2s5_mclk", - [MT2701_AUD_AUD_I2S6_MCLK] = "top_aud_i2s6_mclk", - [MT2701_AUD_ASM_M_SEL] = "top_asm_m_sel", - [MT2701_AUD_ASM_H_SEL] = "top_asm_h_sel", - [MT2701_AUD_UNIVPLL2_D4] = "top_univpll2_d4", - [MT2701_AUD_UNIVPLL2_D2] = "top_univpll2_d2", - [MT2701_AUD_SYSPLL_D5] = "top_syspll_d5", +static const char *const base_clks[] = { + [MT2701_TOP_AUD_MCLK_SRC0] = "top_audio_mux1_sel", + [MT2701_TOP_AUD_MCLK_SRC1] = "top_audio_mux2_sel", + [MT2701_AUDSYS_AFE] = "audio_afe_pd", + [MT2701_AUDSYS_AFE_CONN] = "audio_afe_conn_pd", + [MT2701_AUDSYS_A1SYS] = "audio_a1sys_pd", + [MT2701_AUDSYS_A2SYS] = "audio_a2sys_pd", }; int mt2701_init_clock(struct mtk_base_afe *afe) { struct mt2701_afe_private *afe_priv = afe->platform_priv; - int i = 0; - - for (i = 0; i < MT2701_CLOCK_NUM; i++) { - afe_priv->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]); - if (IS_ERR(afe_priv->clocks[i])) { - dev_warn(afe->dev, "%s devm_clk_get %s fail\n", - __func__, aud_clks[i]); - return PTR_ERR(aud_clks[i]); + int i; + + for (i = 0; i < MT2701_BASE_CLK_NUM; i++) { + afe_priv->base_ck[i] = devm_clk_get(afe->dev, base_clks[i]); + if (IS_ERR(afe_priv->base_ck[i])) { + dev_err(afe->dev, "failed to get %s\n", base_clks[i]); + return PTR_ERR(afe_priv->base_ck[i]); } } - return 0; -} + /* Get I2S related clocks */ + for (i = 0; i < MT2701_I2S_NUM; i++) { + struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[i]; + char name[13]; -int mt2701_afe_enable_clock(struct mtk_base_afe *afe) -{ - int ret = 0; + snprintf(name, sizeof(name), "i2s%d_src_sel", i); + i2s_path->sel_ck = devm_clk_get(afe->dev, name); + if (IS_ERR(i2s_path->sel_ck)) { + dev_err(afe->dev, "failed to get %s\n", name); + return PTR_ERR(i2s_path->sel_ck); + } - ret = mt2701_turn_on_a1sys_clock(afe); - if (ret) { - dev_err(afe->dev, "%s turn_on_a1sys_clock fail %d\n", - __func__, ret); - return ret; - } + snprintf(name, sizeof(name), "i2s%d_src_div", i); + i2s_path->div_ck = devm_clk_get(afe->dev, name); + if (IS_ERR(i2s_path->div_ck)) { + dev_err(afe->dev, "failed to get %s\n", name); + return PTR_ERR(i2s_path->div_ck); + } - ret = mt2701_turn_on_a2sys_clock(afe); - if (ret) { - dev_err(afe->dev, "%s turn_on_a2sys_clock fail %d\n", - __func__, ret); - mt2701_turn_off_a1sys_clock(afe); - return ret; - } + snprintf(name, sizeof(name), "i2s%d_mclk_en", i); + i2s_path->mclk_ck = devm_clk_get(afe->dev, name); + if (IS_ERR(i2s_path->mclk_ck)) { + dev_err(afe->dev, "failed to get %s\n", name); + return PTR_ERR(i2s_path->mclk_ck); + } - ret = mt2701_turn_on_afe_clock(afe); - if (ret) { - dev_err(afe->dev, "%s turn_on_afe_clock fail %d\n", - __func__, ret); - mt2701_turn_off_a1sys_clock(afe); - mt2701_turn_off_a2sys_clock(afe); - return ret; + snprintf(name, sizeof(name), "i2so%d_hop_ck", i); + i2s_path->hop_ck[I2S_OUT] = devm_clk_get(afe->dev, name); + if (IS_ERR(i2s_path->hop_ck[I2S_OUT])) { + dev_err(afe->dev, "failed to get %s\n", name); + return PTR_ERR(i2s_path->hop_ck[I2S_OUT]); + } + + snprintf(name, sizeof(name), "i2si%d_hop_ck", i); + i2s_path->hop_ck[I2S_IN] = devm_clk_get(afe->dev, name); + if (IS_ERR(i2s_path->hop_ck[I2S_IN])) { + dev_err(afe->dev, "failed to get %s\n", name); + return PTR_ERR(i2s_path->hop_ck[I2S_IN]); + } + + snprintf(name, sizeof(name), "asrc%d_out_ck", i); + i2s_path->asrco_ck = devm_clk_get(afe->dev, name); + if (IS_ERR(i2s_path->asrco_ck)) { + dev_err(afe->dev, "failed to get %s\n", name); + return PTR_ERR(i2s_path->asrco_ck); + } } - regmap_update_bits(afe->regmap, ASYS_TOP_CON, - AUDIO_TOP_CON0_A1SYS_A2SYS_ON, - AUDIO_TOP_CON0_A1SYS_A2SYS_ON); - regmap_update_bits(afe->regmap, AFE_DAC_CON0, - AFE_DAC_CON0_AFE_ON, - AFE_DAC_CON0_AFE_ON); - regmap_write(afe->regmap, PWR2_TOP_CON, - PWR2_TOP_CON_INIT_VAL); - regmap_write(afe->regmap, PWR1_ASM_CON1, - PWR1_ASM_CON1_INIT_VAL); - regmap_write(afe->regmap, PWR2_ASM_CON1, - PWR2_ASM_CON1_INIT_VAL); + /* Some platforms may support BT path */ + afe_priv->mrgif_ck = devm_clk_get(afe->dev, "audio_mrgif_pd"); + if (IS_ERR(afe_priv->mrgif_ck)) { + if (PTR_ERR(afe_priv->mrgif_ck) == -EPROBE_DEFER) + return -EPROBE_DEFER; - return 0; -} + afe_priv->mrgif_ck = NULL; + } -void mt2701_afe_disable_clock(struct mtk_base_afe *afe) -{ - mt2701_turn_off_afe_clock(afe); - mt2701_turn_off_a1sys_clock(afe); - mt2701_turn_off_a2sys_clock(afe); - regmap_update_bits(afe->regmap, ASYS_TOP_CON, - AUDIO_TOP_CON0_A1SYS_A2SYS_ON, 0); - regmap_update_bits(afe->regmap, AFE_DAC_CON0, - AFE_DAC_CON0_AFE_ON, 0); + return 0; } -int mt2701_turn_on_a1sys_clock(struct mtk_base_afe *afe) +int mt2701_afe_enable_i2s(struct mtk_base_afe *afe, int id, int dir) { struct mt2701_afe_private *afe_priv = afe->platform_priv; - int ret = 0; + struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id]; + int ret; - /* Set Mux */ - ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]); + ret = clk_prepare_enable(i2s_path->asrco_ck); if (ret) { - dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, aud_clks[MT2701_AUD_AUD_MUX1_SEL], ret); - goto A1SYS_CLK_AUD_MUX1_SEL_ERR; + dev_err(afe->dev, "failed to enable ASRC clock %d\n", ret); + return ret; } - ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL], - afe_priv->clocks[MT2701_AUD_AUD1PLL_98M]); + ret = clk_prepare_enable(i2s_path->hop_ck[dir]); if (ret) { - dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__, - aud_clks[MT2701_AUD_AUD_MUX1_SEL], - aud_clks[MT2701_AUD_AUD1PLL_98M], ret); - goto A1SYS_CLK_AUD_MUX1_SEL_ERR; + dev_err(afe->dev, "failed to enable I2S clock %d\n", ret); + goto err_hop_ck; } - /* Set Divider */ - ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV]); - if (ret) { - dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, - aud_clks[MT2701_AUD_AUD_MUX1_DIV], - ret); - goto A1SYS_CLK_AUD_MUX1_DIV_ERR; - } + return 0; - ret = clk_set_rate(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV], - MT2701_AUD_AUD_MUX1_DIV_RATE); - if (ret) { - dev_err(afe->dev, "%s clk_set_parent %s-%d fail %d\n", __func__, - aud_clks[MT2701_AUD_AUD_MUX1_DIV], - MT2701_AUD_AUD_MUX1_DIV_RATE, ret); - goto A1SYS_CLK_AUD_MUX1_DIV_ERR; - } +err_hop_ck: + clk_disable_unprepare(i2s_path->asrco_ck); - /* Enable clock gate */ - ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_48K_TIMING]); - if (ret) { - dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, aud_clks[MT2701_AUD_AUD_48K_TIMING], ret); - goto A1SYS_CLK_AUD_48K_ERR; - } + return ret; +} - /* Enable infra audio */ - ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); - if (ret) { - dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret); - goto A1SYS_CLK_INFRA_ERR; - } +void mt2701_afe_disable_i2s(struct mtk_base_afe *afe, int id, int dir) +{ + struct mt2701_afe_private *afe_priv = afe->platform_priv; + struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id]; - return 0; + clk_disable_unprepare(i2s_path->hop_ck[dir]); + clk_disable_unprepare(i2s_path->asrco_ck); +} -A1SYS_CLK_INFRA_ERR: - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); -A1SYS_CLK_AUD_48K_ERR: - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_48K_TIMING]); -A1SYS_CLK_AUD_MUX1_DIV_ERR: - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV]); -A1SYS_CLK_AUD_MUX1_SEL_ERR: - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]); +int mt2701_afe_enable_mclk(struct mtk_base_afe *afe, int id) +{ + struct mt2701_afe_private *afe_priv = afe->platform_priv; + struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id]; - return ret; + return clk_prepare_enable(i2s_path->mclk_ck); } -void mt2701_turn_off_a1sys_clock(struct mtk_base_afe *afe) +void mt2701_afe_disable_mclk(struct mtk_base_afe *afe, int id) { struct mt2701_afe_private *afe_priv = afe->platform_priv; + struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id]; - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_48K_TIMING]); - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV]); - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]); + clk_disable_unprepare(i2s_path->mclk_ck); } -int mt2701_turn_on_a2sys_clock(struct mtk_base_afe *afe) +int mt2701_enable_btmrg_clk(struct mtk_base_afe *afe) { struct mt2701_afe_private *afe_priv = afe->platform_priv; - int ret = 0; - /* Set Mux */ - ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]); - if (ret) { - dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, aud_clks[MT2701_AUD_AUD_MUX2_SEL], ret); - goto A2SYS_CLK_AUD_MUX2_SEL_ERR; - } + return clk_prepare_enable(afe_priv->mrgif_ck); +} - ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL], - afe_priv->clocks[MT2701_AUD_AUD2PLL_90M]); - if (ret) { - dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__, - aud_clks[MT2701_AUD_AUD_MUX2_SEL], - aud_clks[MT2701_AUD_AUD2PLL_90M], ret); - goto A2SYS_CLK_AUD_MUX2_SEL_ERR; - } +void mt2701_disable_btmrg_clk(struct mtk_base_afe *afe) +{ + struct mt2701_afe_private *afe_priv = afe->platform_priv; - /* Set Divider */ - ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV]); - if (ret) { - dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, aud_clks[MT2701_AUD_AUD_MUX2_DIV], ret); - goto A2SYS_CLK_AUD_MUX2_DIV_ERR; - } + clk_disable_unprepare(afe_priv->mrgif_ck); +} - ret = clk_set_rate(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV], - MT2701_AUD_AUD_MUX2_DIV_RATE); - if (ret) { - dev_err(afe->dev, "%s clk_set_parent %s-%d fail %d\n", __func__, - aud_clks[MT2701_AUD_AUD_MUX2_DIV], - MT2701_AUD_AUD_MUX2_DIV_RATE, ret); - goto A2SYS_CLK_AUD_MUX2_DIV_ERR; - } +static int mt2701_afe_enable_audsys(struct mtk_base_afe *afe) +{ + struct mt2701_afe_private *afe_priv = afe->platform_priv; + int ret; - /* Enable clock gate */ - ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_44K_TIMING]); - if (ret) { - dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, aud_clks[MT2701_AUD_AUD_44K_TIMING], ret); - goto A2SYS_CLK_AUD_44K_ERR; - } + ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_AFE]); + if (ret) + return ret; - /* Enable infra audio */ - ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); - if (ret) { - dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret); - goto A2SYS_CLK_INFRA_ERR; - } + ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]); + if (ret) + goto err_audio_a1sys; + + ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]); + if (ret) + goto err_audio_a2sys; + + ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_AFE_CONN]); + if (ret) + goto err_afe_conn; return 0; -A2SYS_CLK_INFRA_ERR: - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); -A2SYS_CLK_AUD_44K_ERR: - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_44K_TIMING]); -A2SYS_CLK_AUD_MUX2_DIV_ERR: - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV]); -A2SYS_CLK_AUD_MUX2_SEL_ERR: - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]); +err_afe_conn: + clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]); +err_audio_a2sys: + clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]); +err_audio_a1sys: + clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE]); return ret; } -void mt2701_turn_off_a2sys_clock(struct mtk_base_afe *afe) +static void mt2701_afe_disable_audsys(struct mtk_base_afe *afe) { struct mt2701_afe_private *afe_priv = afe->platform_priv; - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_44K_TIMING]); - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV]); - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]); + clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE_CONN]); + clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]); + clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]); + clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE]); } -int mt2701_turn_on_afe_clock(struct mtk_base_afe *afe) +int mt2701_afe_enable_clock(struct mtk_base_afe *afe) { - struct mt2701_afe_private *afe_priv = afe->platform_priv; int ret; - /* enable INFRA_SYS */ - ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); - if (ret) { - dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret); - goto AFE_AUD_INFRA_ERR; - } - - /* Set MT2701_AUD_AUDINTBUS to MT2701_AUD_SYSPLL1_D4 */ - ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUDINTBUS]); - if (ret) { - dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, aud_clks[MT2701_AUD_AUDINTBUS], ret); - goto AFE_AUD_AUDINTBUS_ERR; - } - - ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_AUDINTBUS], - afe_priv->clocks[MT2701_AUD_SYSPLL1_D4]); - if (ret) { - dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__, - aud_clks[MT2701_AUD_AUDINTBUS], - aud_clks[MT2701_AUD_SYSPLL1_D4], ret); - goto AFE_AUD_AUDINTBUS_ERR; - } - - /* Set MT2701_AUD_ASM_H_SEL to MT2701_AUD_UNIVPLL2_D2 */ - ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_ASM_H_SEL]); - if (ret) { - dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, aud_clks[MT2701_AUD_ASM_H_SEL], ret); - goto AFE_AUD_ASM_H_ERR; - } - - ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_ASM_H_SEL], - afe_priv->clocks[MT2701_AUD_UNIVPLL2_D2]); - if (ret) { - dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__, - aud_clks[MT2701_AUD_ASM_H_SEL], - aud_clks[MT2701_AUD_UNIVPLL2_D2], ret); - goto AFE_AUD_ASM_H_ERR; - } - - /* Set MT2701_AUD_ASM_M_SEL to MT2701_AUD_UNIVPLL2_D4 */ - ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_ASM_M_SEL]); + /* Enable audio system */ + ret = mt2701_afe_enable_audsys(afe); if (ret) { - dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, aud_clks[MT2701_AUD_ASM_M_SEL], ret); - goto AFE_AUD_ASM_M_ERR; + dev_err(afe->dev, "failed to enable audio system %d\n", ret); + return ret; } - ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_ASM_M_SEL], - afe_priv->clocks[MT2701_AUD_UNIVPLL2_D4]); - if (ret) { - dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__, - aud_clks[MT2701_AUD_ASM_M_SEL], - aud_clks[MT2701_AUD_UNIVPLL2_D4], ret); - goto AFE_AUD_ASM_M_ERR; - } + regmap_update_bits(afe->regmap, ASYS_TOP_CON, + AUDIO_TOP_CON0_A1SYS_A2SYS_ON, + AUDIO_TOP_CON0_A1SYS_A2SYS_ON); + regmap_update_bits(afe->regmap, AFE_DAC_CON0, + AFE_DAC_CON0_AFE_ON, + AFE_DAC_CON0_AFE_ON); - regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, - AUDIO_TOP_CON0_PDN_AFE, 0); - regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, - AUDIO_TOP_CON0_PDN_APLL_CK, 0); - regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, - AUDIO_TOP_CON4_PDN_A1SYS, 0); - regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, - AUDIO_TOP_CON4_PDN_A2SYS, 0); - regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, - AUDIO_TOP_CON4_PDN_AFE_CONN, 0); + /* Configure ASRC */ + regmap_write(afe->regmap, PWR1_ASM_CON1, PWR1_ASM_CON1_INIT_VAL); + regmap_write(afe->regmap, PWR2_ASM_CON1, PWR2_ASM_CON1_INIT_VAL); return 0; - -AFE_AUD_ASM_M_ERR: - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_M_SEL]); -AFE_AUD_ASM_H_ERR: - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_H_SEL]); -AFE_AUD_AUDINTBUS_ERR: - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUDINTBUS]); -AFE_AUD_INFRA_ERR: - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); - - return ret; } -void mt2701_turn_off_afe_clock(struct mtk_base_afe *afe) +int mt2701_afe_disable_clock(struct mtk_base_afe *afe) { - struct mt2701_afe_private *afe_priv = afe->platform_priv; + regmap_update_bits(afe->regmap, ASYS_TOP_CON, + AUDIO_TOP_CON0_A1SYS_A2SYS_ON, 0); + regmap_update_bits(afe->regmap, AFE_DAC_CON0, + AFE_DAC_CON0_AFE_ON, 0); - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); - - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUDINTBUS]); - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_H_SEL]); - clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_M_SEL]); - - regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, - AUDIO_TOP_CON0_PDN_AFE, AUDIO_TOP_CON0_PDN_AFE); - regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, - AUDIO_TOP_CON0_PDN_APLL_CK, - AUDIO_TOP_CON0_PDN_APLL_CK); - regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, - AUDIO_TOP_CON4_PDN_A1SYS, - AUDIO_TOP_CON4_PDN_A1SYS); - regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, - AUDIO_TOP_CON4_PDN_A2SYS, - AUDIO_TOP_CON4_PDN_A2SYS); - regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, - AUDIO_TOP_CON4_PDN_AFE_CONN, - AUDIO_TOP_CON4_PDN_AFE_CONN); + mt2701_afe_disable_audsys(afe); + + return 0; } void mt2701_mclk_configuration(struct mtk_base_afe *afe, int id, int domain, int mclk) { - struct mt2701_afe_private *afe_priv = afe->platform_priv; + struct mt2701_afe_private *priv = afe->platform_priv; + struct mt2701_i2s_path *i2s_path = &priv->i2s_path[id]; int ret; - int aud_src_div_id = MT2701_AUD_AUD_K1_SRC_DIV + id; - int aud_src_clk_id = MT2701_AUD_AUD_K1_SRC_SEL + id; - /* Set MCLK Kx_SRC_SEL(domain) */ - ret = clk_prepare_enable(afe_priv->clocks[aud_src_clk_id]); - if (ret) - dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, aud_clks[aud_src_clk_id], ret); - - if (domain == 0) { - ret = clk_set_parent(afe_priv->clocks[aud_src_clk_id], - afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]); - if (ret) - dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", - __func__, aud_clks[aud_src_clk_id], - aud_clks[MT2701_AUD_AUD_MUX1_SEL], ret); - } else { - ret = clk_set_parent(afe_priv->clocks[aud_src_clk_id], - afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]); - if (ret) - dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", - __func__, aud_clks[aud_src_clk_id], - aud_clks[MT2701_AUD_AUD_MUX2_SEL], ret); - } - clk_disable_unprepare(afe_priv->clocks[aud_src_clk_id]); + /* Set mclk source */ + if (domain == 0) + ret = clk_set_parent(i2s_path->sel_ck, + priv->base_ck[MT2701_TOP_AUD_MCLK_SRC0]); + else + ret = clk_set_parent(i2s_path->sel_ck, + priv->base_ck[MT2701_TOP_AUD_MCLK_SRC1]); - /* Set MCLK Kx_SRC_DIV(divider) */ - ret = clk_prepare_enable(afe_priv->clocks[aud_src_div_id]); if (ret) - dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, aud_clks[aud_src_div_id], ret); + dev_err(afe->dev, "failed to set domain%d mclk source %d\n", + domain, ret); - ret = clk_set_rate(afe_priv->clocks[aud_src_div_id], mclk); + /* Set mclk divider */ + ret = clk_set_rate(i2s_path->div_ck, mclk); if (ret) - dev_err(afe->dev, "%s clk_set_rate %s-%d fail %d\n", __func__, - aud_clks[aud_src_div_id], mclk, ret); - clk_disable_unprepare(afe_priv->clocks[aud_src_div_id]); + dev_err(afe->dev, "failed to set mclk divider %d\n", ret); } MODULE_DESCRIPTION("MT2701 afe clock control"); diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h index 6497d570cf09..15417d9d6597 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h +++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h @@ -21,16 +21,15 @@ struct mtk_base_afe; int mt2701_init_clock(struct mtk_base_afe *afe); int mt2701_afe_enable_clock(struct mtk_base_afe *afe); -void mt2701_afe_disable_clock(struct mtk_base_afe *afe); +int mt2701_afe_disable_clock(struct mtk_base_afe *afe); -int mt2701_turn_on_a1sys_clock(struct mtk_base_afe *afe); -void mt2701_turn_off_a1sys_clock(struct mtk_base_afe *afe); +int mt2701_afe_enable_i2s(struct mtk_base_afe *afe, int id, int dir); +void mt2701_afe_disable_i2s(struct mtk_base_afe *afe, int id, int dir); +int mt2701_afe_enable_mclk(struct mtk_base_afe *afe, int id); +void mt2701_afe_disable_mclk(struct mtk_base_afe *afe, int id); -int mt2701_turn_on_a2sys_clock(struct mtk_base_afe *afe); -void mt2701_turn_off_a2sys_clock(struct mtk_base_afe *afe); - -int mt2701_turn_on_afe_clock(struct mtk_base_afe *afe); -void mt2701_turn_off_afe_clock(struct mtk_base_afe *afe); +int mt2701_enable_btmrg_clk(struct mtk_base_afe *afe); +void mt2701_disable_btmrg_clk(struct mtk_base_afe *afe); void mt2701_mclk_configuration(struct mtk_base_afe *afe, int id, int domain, int mclk); diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-common.h b/sound/soc/mediatek/mt2701/mt2701-afe-common.h index c19430e98adf..ce5bd4dc864d 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-common.h +++ b/sound/soc/mediatek/mt2701/mt2701-afe-common.h @@ -69,53 +69,14 @@ enum { MT2701_IRQ_ASYS_END, }; -/* 2701 clock def */ -enum audio_system_clock_type { - MT2701_AUD_INFRA_SYS_AUDIO, - MT2701_AUD_AUD_MUX1_SEL, - MT2701_AUD_AUD_MUX2_SEL, - MT2701_AUD_AUD_MUX1_DIV, - MT2701_AUD_AUD_MUX2_DIV, - MT2701_AUD_AUD_48K_TIMING, - MT2701_AUD_AUD_44K_TIMING, - MT2701_AUD_AUDPLL_MUX_SEL, - MT2701_AUD_APLL_SEL, - MT2701_AUD_AUD1PLL_98M, - MT2701_AUD_AUD2PLL_90M, - MT2701_AUD_HADDS2PLL_98M, - MT2701_AUD_HADDS2PLL_294M, - MT2701_AUD_AUDPLL, - MT2701_AUD_AUDPLL_D4, - MT2701_AUD_AUDPLL_D8, - MT2701_AUD_AUDPLL_D16, - MT2701_AUD_AUDPLL_D24, - MT2701_AUD_AUDINTBUS, - MT2701_AUD_CLK_26M, - MT2701_AUD_SYSPLL1_D4, - MT2701_AUD_AUD_K1_SRC_SEL, - MT2701_AUD_AUD_K2_SRC_SEL, - MT2701_AUD_AUD_K3_SRC_SEL, - MT2701_AUD_AUD_K4_SRC_SEL, - MT2701_AUD_AUD_K5_SRC_SEL, - MT2701_AUD_AUD_K6_SRC_SEL, - MT2701_AUD_AUD_K1_SRC_DIV, - MT2701_AUD_AUD_K2_SRC_DIV, - MT2701_AUD_AUD_K3_SRC_DIV, - MT2701_AUD_AUD_K4_SRC_DIV, - MT2701_AUD_AUD_K5_SRC_DIV, - MT2701_AUD_AUD_K6_SRC_DIV, - MT2701_AUD_AUD_I2S1_MCLK, - MT2701_AUD_AUD_I2S2_MCLK, - MT2701_AUD_AUD_I2S3_MCLK, - MT2701_AUD_AUD_I2S4_MCLK, - MT2701_AUD_AUD_I2S5_MCLK, - MT2701_AUD_AUD_I2S6_MCLK, - MT2701_AUD_ASM_M_SEL, - MT2701_AUD_ASM_H_SEL, - MT2701_AUD_UNIVPLL2_D4, - MT2701_AUD_UNIVPLL2_D2, - MT2701_AUD_SYSPLL_D5, - MT2701_CLOCK_NUM +enum audio_base_clock { + MT2701_TOP_AUD_MCLK_SRC0, + MT2701_TOP_AUD_MCLK_SRC1, + MT2701_AUDSYS_AFE, + MT2701_AUDSYS_AFE_CONN, + MT2701_AUDSYS_A1SYS, + MT2701_AUDSYS_A2SYS, + MT2701_BASE_CLK_NUM, }; static const unsigned int mt2701_afe_backup_list[] = { @@ -144,7 +105,6 @@ struct mtk_base_irq_data; struct mt2701_i2s_data { int i2s_ctrl_reg; - int i2s_pwn_shift; int i2s_asrc_fs_shift; int i2s_asrc_fs_mask; }; @@ -161,11 +121,17 @@ struct mt2701_i2s_path { int on[I2S_DIR_NUM]; int occupied[I2S_DIR_NUM]; const struct mt2701_i2s_data *i2s_data[2]; + struct clk *hop_ck[I2S_DIR_NUM]; + struct clk *sel_ck; + struct clk *div_ck; + struct clk *mclk_ck; + struct clk *asrco_ck; }; struct mt2701_afe_private { - struct clk *clocks[MT2701_CLOCK_NUM]; struct mt2701_i2s_path i2s_path[MT2701_I2S_NUM]; + struct clk *base_ck[MT2701_BASE_CLK_NUM]; + struct clk *mrgif_ck; bool mrg_enable[MT2701_STREAM_DIR_NUM]; }; diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c index a7362d1cda1b..33f809228f25 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -97,21 +97,12 @@ static int mt2701_afe_i2s_startup(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); - struct mt2701_afe_private *afe_priv = afe->platform_priv; int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); - int clk_num = MT2701_AUD_AUD_I2S1_MCLK + i2s_num; - int ret = 0; if (i2s_num < 0) return i2s_num; - /* enable mclk */ - ret = clk_prepare_enable(afe_priv->clocks[clk_num]); - if (ret) - dev_err(afe->dev, "Failed to enable mclk for I2S: %d\n", - i2s_num); - - return ret; + return mt2701_afe_enable_mclk(afe, i2s_num); } static int mt2701_afe_i2s_path_shutdown(struct snd_pcm_substream *substream, @@ -151,9 +142,9 @@ static int mt2701_afe_i2s_path_shutdown(struct snd_pcm_substream *substream, /* disable i2s */ regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, ASYS_I2S_CON_I2S_EN, 0); - regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, - 1 << i2s_data->i2s_pwn_shift, - 1 << i2s_data->i2s_pwn_shift); + + mt2701_afe_disable_i2s(afe, i2s_num, stream_dir); + return 0; } @@ -165,7 +156,6 @@ static void mt2701_afe_i2s_shutdown(struct snd_pcm_substream *substream, struct mt2701_afe_private *afe_priv = afe->platform_priv; int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); struct mt2701_i2s_path *i2s_path; - int clk_num = MT2701_AUD_AUD_I2S1_MCLK + i2s_num; if (i2s_num < 0) return; @@ -185,7 +175,7 @@ static void mt2701_afe_i2s_shutdown(struct snd_pcm_substream *substream, I2S_UNSTART: /* disable mclk */ - clk_disable_unprepare(afe_priv->clocks[clk_num]); + mt2701_afe_disable_mclk(afe, i2s_num); } static int mt2701_i2s_path_prepare_enable(struct snd_pcm_substream *substream, @@ -251,9 +241,7 @@ static int mt2701_i2s_path_prepare_enable(struct snd_pcm_substream *substream, fs << i2s_data->i2s_asrc_fs_shift); /* enable i2s */ - regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, - 1 << i2s_data->i2s_pwn_shift, - 0 << i2s_data->i2s_pwn_shift); + mt2701_afe_enable_i2s(afe, i2s_num, stream_dir); /* reset i2s hw status before enable */ regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, @@ -339,9 +327,11 @@ static int mt2701_btmrg_startup(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); struct mt2701_afe_private *afe_priv = afe->platform_priv; + int ret; - regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, - AUDIO_TOP_CON4_PDN_MRGIF, 0); + ret = mt2701_enable_btmrg_clk(afe); + if (ret) + return ret; afe_priv->mrg_enable[substream->stream] = 1; return 0; @@ -406,9 +396,7 @@ static void mt2701_btmrg_shutdown(struct snd_pcm_substream *substream, AFE_MRGIF_CON_MRG_EN, 0); regmap_update_bits(afe->regmap, AFE_MRGIF_CON, AFE_MRGIF_CON_MRG_I2S_EN, 0); - regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, - AUDIO_TOP_CON4_PDN_MRGIF, - AUDIO_TOP_CON4_PDN_MRGIF); + mt2701_disable_btmrg_clk(afe); } afe_priv->mrg_enable[substream->stream] = 0; } @@ -1386,14 +1374,12 @@ static const struct mt2701_i2s_data mt2701_i2s_data[MT2701_I2S_NUM][2] = { { { .i2s_ctrl_reg = ASYS_I2SO1_CON, - .i2s_pwn_shift = 6, .i2s_asrc_fs_shift = 0, .i2s_asrc_fs_mask = 0x1f, }, { .i2s_ctrl_reg = ASYS_I2SIN1_CON, - .i2s_pwn_shift = 0, .i2s_asrc_fs_shift = 0, .i2s_asrc_fs_mask = 0x1f, @@ -1402,14 +1388,12 @@ static const struct mt2701_i2s_data mt2701_i2s_data[MT2701_I2S_NUM][2] = { { { .i2s_ctrl_reg = ASYS_I2SO2_CON, - .i2s_pwn_shift = 7, .i2s_asrc_fs_shift = 5, .i2s_asrc_fs_mask = 0x1f, }, { .i2s_ctrl_reg = ASYS_I2SIN2_CON, - .i2s_pwn_shift = 1, .i2s_asrc_fs_shift = 5, .i2s_asrc_fs_mask = 0x1f, @@ -1418,14 +1402,12 @@ static const struct mt2701_i2s_data mt2701_i2s_data[MT2701_I2S_NUM][2] = { { { .i2s_ctrl_reg = ASYS_I2SO3_CON, - .i2s_pwn_shift = 8, .i2s_asrc_fs_shift = 10, .i2s_asrc_fs_mask = 0x1f, }, { .i2s_ctrl_reg = ASYS_I2SIN3_CON, - .i2s_pwn_shift = 2, .i2s_asrc_fs_shift = 10, .i2s_asrc_fs_mask = 0x1f, @@ -1434,14 +1416,12 @@ static const struct mt2701_i2s_data mt2701_i2s_data[MT2701_I2S_NUM][2] = { { { .i2s_ctrl_reg = ASYS_I2SO4_CON, - .i2s_pwn_shift = 9, .i2s_asrc_fs_shift = 15, .i2s_asrc_fs_mask = 0x1f, }, { .i2s_ctrl_reg = ASYS_I2SIN4_CON, - .i2s_pwn_shift = 3, .i2s_asrc_fs_shift = 15, .i2s_asrc_fs_mask = 0x1f, @@ -1483,8 +1463,7 @@ static int mt2701_afe_runtime_suspend(struct device *dev) { struct mtk_base_afe *afe = dev_get_drvdata(dev); - mt2701_afe_disable_clock(afe); - return 0; + return mt2701_afe_disable_clock(afe); } static int mt2701_afe_runtime_resume(struct device *dev) -- cgit v1.2.3 From 600b2fd4f0f7ae5ebcb604c39c9a97e573f9d23e Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 2 Jan 2018 19:47:20 +0800 Subject: ASoC: mediatek: cleanup audio driver for MT2701 Cleanup unused code such as 'i2s_num' guard, headers, indentation and some defines. Signed-off-by: Ryder Lee Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c | 14 +--- sound/soc/mediatek/mt2701/mt2701-afe-common.h | 20 +---- sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 94 ++++------------------- sound/soc/mediatek/mt2701/mt2701-reg.h | 41 +--------- 4 files changed, 24 insertions(+), 145 deletions(-) diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c index 75ccdca5811d..56a057c78c9a 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c @@ -14,10 +14,6 @@ * GNU General Public License for more details. */ -#include -#include -#include - #include "mt2701-afe-common.h" #include "mt2701-afe-clock-ctrl.h" @@ -223,8 +219,8 @@ int mt2701_afe_enable_clock(struct mtk_base_afe *afe) } regmap_update_bits(afe->regmap, ASYS_TOP_CON, - AUDIO_TOP_CON0_A1SYS_A2SYS_ON, - AUDIO_TOP_CON0_A1SYS_A2SYS_ON); + ASYS_TOP_CON_ASYS_TIMING_ON, + ASYS_TOP_CON_ASYS_TIMING_ON); regmap_update_bits(afe->regmap, AFE_DAC_CON0, AFE_DAC_CON0_AFE_ON, AFE_DAC_CON0_AFE_ON); @@ -239,7 +235,7 @@ int mt2701_afe_enable_clock(struct mtk_base_afe *afe) int mt2701_afe_disable_clock(struct mtk_base_afe *afe) { regmap_update_bits(afe->regmap, ASYS_TOP_CON, - AUDIO_TOP_CON0_A1SYS_A2SYS_ON, 0); + ASYS_TOP_CON_ASYS_TIMING_ON, 0); regmap_update_bits(afe->regmap, AFE_DAC_CON0, AFE_DAC_CON0_AFE_ON, 0); @@ -272,7 +268,3 @@ void mt2701_mclk_configuration(struct mtk_base_afe *afe, int id, int domain, if (ret) dev_err(afe->dev, "failed to set mclk divider %d\n", ret); } - -MODULE_DESCRIPTION("MT2701 afe clock control"); -MODULE_AUTHOR("Garlic Tseng "); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-common.h b/sound/soc/mediatek/mt2701/mt2701-afe-common.h index ce5bd4dc864d..9a2b301a4c21 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-common.h +++ b/sound/soc/mediatek/mt2701/mt2701-afe-common.h @@ -16,6 +16,7 @@ #ifndef _MT_2701_AFE_COMMON_H_ #define _MT_2701_AFE_COMMON_H_ + #include #include #include @@ -25,16 +26,7 @@ #define MT2701_STREAM_DIR_NUM (SNDRV_PCM_STREAM_LAST + 1) #define MT2701_PLL_DOMAIN_0_RATE 98304000 #define MT2701_PLL_DOMAIN_1_RATE 90316800 -#define MT2701_AUD_AUD_MUX1_DIV_RATE (MT2701_PLL_DOMAIN_0_RATE / 2) -#define MT2701_AUD_AUD_MUX2_DIV_RATE (MT2701_PLL_DOMAIN_1_RATE / 2) - -enum { - MT2701_I2S_1, - MT2701_I2S_2, - MT2701_I2S_3, - MT2701_I2S_4, - MT2701_I2S_NUM, -}; +#define MT2701_I2S_NUM 4 enum { MT2701_MEMIF_DL1, @@ -62,8 +54,7 @@ enum { }; enum { - MT2701_IRQ_ASYS_START, - MT2701_IRQ_ASYS_IRQ1 = MT2701_IRQ_ASYS_START, + MT2701_IRQ_ASYS_IRQ1, MT2701_IRQ_ASYS_IRQ2, MT2701_IRQ_ASYS_IRQ3, MT2701_IRQ_ASYS_END, @@ -100,9 +91,6 @@ static const unsigned int mt2701_afe_backup_list[] = { AFE_MEMIF_PBUF_SIZE, }; -struct snd_pcm_substream; -struct mtk_base_irq_data; - struct mt2701_i2s_data { int i2s_ctrl_reg; int i2s_asrc_fs_shift; @@ -120,7 +108,7 @@ struct mt2701_i2s_path { int mclk_rate; int on[I2S_DIR_NUM]; int occupied[I2S_DIR_NUM]; - const struct mt2701_i2s_data *i2s_data[2]; + const struct mt2701_i2s_data *i2s_data[I2S_DIR_NUM]; struct clk *hop_ck[I2S_DIR_NUM]; struct clk *sel_ck; struct clk *div_ck; diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c index 33f809228f25..0edadca12a5e 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -20,16 +20,12 @@ #include #include #include -#include #include "mt2701-afe-common.h" - #include "mt2701-afe-clock-ctrl.h" #include "../common/mtk-afe-platform-driver.h" #include "../common/mtk-afe-fe-dai.h" -#define AFE_IRQ_STATUS_BITS 0xff - static const struct snd_pcm_hardware mt2701_afe_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID, @@ -107,21 +103,16 @@ static int mt2701_afe_i2s_startup(struct snd_pcm_substream *substream, static int mt2701_afe_i2s_path_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, + int i2s_num, int dir_invert) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); struct mt2701_afe_private *afe_priv = afe->platform_priv; - int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); - struct mt2701_i2s_path *i2s_path; + struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[i2s_num]; const struct mt2701_i2s_data *i2s_data; int stream_dir = substream->stream; - if (i2s_num < 0) - return i2s_num; - - i2s_path = &afe_priv->i2s_path[i2s_num]; - if (dir_invert) { if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) stream_dir = SNDRV_PCM_STREAM_CAPTURE; @@ -167,11 +158,11 @@ static void mt2701_afe_i2s_shutdown(struct snd_pcm_substream *substream, else goto I2S_UNSTART; - mt2701_afe_i2s_path_shutdown(substream, dai, 0); + mt2701_afe_i2s_path_shutdown(substream, dai, i2s_num, 0); /* need to disable i2s-out path when disable i2s-in */ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - mt2701_afe_i2s_path_shutdown(substream, dai, 1); + mt2701_afe_i2s_path_shutdown(substream, dai, i2s_num, 1); I2S_UNSTART: /* disable mclk */ @@ -180,24 +171,19 @@ I2S_UNSTART: static int mt2701_i2s_path_prepare_enable(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, + int i2s_num, int dir_invert) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); struct mt2701_afe_private *afe_priv = afe->platform_priv; - int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); - struct mt2701_i2s_path *i2s_path; + struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[i2s_num]; const struct mt2701_i2s_data *i2s_data; struct snd_pcm_runtime * const runtime = substream->runtime; int reg, fs, w_len = 1; /* now we support bck 64bits only */ int stream_dir = substream->stream; unsigned int mask = 0, val = 0; - if (i2s_num < 0) - return i2s_num; - - i2s_path = &afe_priv->i2s_path[i2s_num]; - if (dir_invert) { if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) stream_dir = SNDRV_PCM_STREAM_CAPTURE; @@ -288,13 +274,13 @@ static int mt2701_afe_i2s_prepare(struct snd_pcm_substream *substream, mt2701_mclk_configuration(afe, i2s_num, clk_domain, mclk_rate); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - mt2701_i2s_path_prepare_enable(substream, dai, 0); + mt2701_i2s_path_prepare_enable(substream, dai, i2s_num, 0); } else { /* need to enable i2s-out path when enable i2s-in */ /* prepare for another direction "out" */ - mt2701_i2s_path_prepare_enable(substream, dai, 1); + mt2701_i2s_path_prepare_enable(substream, dai, i2s_num, 1); /* prepare for "in" */ - mt2701_i2s_path_prepare_enable(substream, dai, 0); + mt2701_i2s_path_prepare_enable(substream, dai, i2s_num, 0); } return 0; @@ -562,7 +548,6 @@ static const struct snd_soc_dai_ops mt2701_single_memif_dai_ops = { .hw_free = mtk_afe_fe_hw_free, .prepare = mtk_afe_fe_prepare, .trigger = mtk_afe_fe_trigger, - }; static const struct snd_soc_dai_ops mt2701_dlm_memif_dai_ops = { @@ -903,31 +888,6 @@ static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s4[] = { PWR2_TOP_CON, 19, 1, 0), }; -static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc0[] = { - SOC_DAPM_SINGLE_AUTODISABLE("Asrc0 out Switch", AUDIO_TOP_CON4, 14, 1, - 1), -}; - -static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc1[] = { - SOC_DAPM_SINGLE_AUTODISABLE("Asrc1 out Switch", AUDIO_TOP_CON4, 15, 1, - 1), -}; - -static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc2[] = { - SOC_DAPM_SINGLE_AUTODISABLE("Asrc2 out Switch", PWR2_TOP_CON, 6, 1, - 1), -}; - -static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc3[] = { - SOC_DAPM_SINGLE_AUTODISABLE("Asrc3 out Switch", PWR2_TOP_CON, 7, 1, - 1), -}; - -static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc4[] = { - SOC_DAPM_SINGLE_AUTODISABLE("Asrc4 out Switch", PWR2_TOP_CON, 8, 1, - 1), -}; - static const struct snd_soc_dapm_widget mt2701_afe_pcm_widgets[] = { /* inter-connections */ SND_SOC_DAPM_MIXER("I00", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -987,19 +947,6 @@ static const struct snd_soc_dapm_widget mt2701_afe_pcm_widgets[] = { SND_SOC_DAPM_MIXER("I18I19", SND_SOC_NOPM, 0, 0, mt2701_afe_multi_ch_out_i2s3, ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s3)), - - SND_SOC_DAPM_MIXER("ASRC_O0", SND_SOC_NOPM, 0, 0, - mt2701_afe_multi_ch_out_asrc0, - ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc0)), - SND_SOC_DAPM_MIXER("ASRC_O1", SND_SOC_NOPM, 0, 0, - mt2701_afe_multi_ch_out_asrc1, - ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc1)), - SND_SOC_DAPM_MIXER("ASRC_O2", SND_SOC_NOPM, 0, 0, - mt2701_afe_multi_ch_out_asrc2, - ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc2)), - SND_SOC_DAPM_MIXER("ASRC_O3", SND_SOC_NOPM, 0, 0, - mt2701_afe_multi_ch_out_asrc3, - ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc3)), }; static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = { @@ -1009,7 +956,6 @@ static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = { {"I2S0 Playback", NULL, "O15"}, {"I2S0 Playback", NULL, "O16"}, - {"I2S1 Playback", NULL, "O17"}, {"I2S1 Playback", NULL, "O18"}, {"I2S2 Playback", NULL, "O19"}, @@ -1026,7 +972,6 @@ static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = { {"I00", NULL, "I2S0 Capture"}, {"I01", NULL, "I2S0 Capture"}, - {"I02", NULL, "I2S1 Capture"}, {"I03", NULL, "I2S1 Capture"}, /* I02,03 link to UL2, also need to open I2S0 */ @@ -1034,15 +979,10 @@ static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = { {"I26", NULL, "BT Capture"}, - {"ASRC_O0", "Asrc0 out Switch", "DLM"}, - {"ASRC_O1", "Asrc1 out Switch", "DLM"}, - {"ASRC_O2", "Asrc2 out Switch", "DLM"}, - {"ASRC_O3", "Asrc3 out Switch", "DLM"}, - - {"I12I13", "Multich I2S0 Out Switch", "ASRC_O0"}, - {"I14I15", "Multich I2S1 Out Switch", "ASRC_O1"}, - {"I16I17", "Multich I2S2 Out Switch", "ASRC_O2"}, - {"I18I19", "Multich I2S3 Out Switch", "ASRC_O3"}, + {"I12I13", "Multich I2S0 Out Switch", "DLM"}, + {"I14I15", "Multich I2S1 Out Switch", "DLM"}, + {"I16I17", "Multich I2S2 Out Switch", "DLM"}, + {"I18I19", "Multich I2S3 Out Switch", "DLM"}, { "I12", NULL, "I12I13" }, { "I13", NULL, "I12I13" }, @@ -1067,7 +1007,6 @@ static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = { { "O21", "I18 Switch", "I18" }, { "O22", "I19 Switch", "I19" }, { "O31", "I35 Switch", "I35" }, - }; static const struct snd_soc_component_driver mt2701_afe_pcm_dai_component = { @@ -1484,12 +1423,13 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); if (!afe) return -ENOMEM; + afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv), GFP_KERNEL); if (!afe->platform_priv) return -ENOMEM; - afe_priv = afe->platform_priv; + afe_priv = afe->platform_priv; afe->dev = &pdev->dev; dev = afe->dev; @@ -1524,7 +1464,6 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) afe->memif_size = MT2701_MEMIF_NUM; afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif), GFP_KERNEL); - if (!afe->memif) return -ENOMEM; @@ -1537,7 +1476,6 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) afe->irqs_size = MT2701_IRQ_ASYS_END; afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs), GFP_KERNEL); - if (!afe->irqs) return -ENOMEM; @@ -1555,7 +1493,6 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) afe->mtk_afe_hardware = &mt2701_afe_hardware; afe->memif_fs = mt2701_memif_fs; afe->irq_fs = mt2701_irq_fs; - afe->reg_back_up_list = mt2701_afe_backup_list; afe->reg_back_up_list_num = ARRAY_SIZE(mt2701_afe_backup_list); afe->runtime_resume = mt2701_afe_runtime_resume; @@ -1646,4 +1583,3 @@ module_platform_driver(mt2701_afe_pcm_driver); MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 2701"); MODULE_AUTHOR("Garlic Tseng "); MODULE_LICENSE("GPL v2"); - diff --git a/sound/soc/mediatek/mt2701/mt2701-reg.h b/sound/soc/mediatek/mt2701/mt2701-reg.h index bb62b1c55957..f17c76f37b5f 100644 --- a/sound/soc/mediatek/mt2701/mt2701-reg.h +++ b/sound/soc/mediatek/mt2701/mt2701-reg.h @@ -17,17 +17,6 @@ #ifndef _MT2701_REG_H_ #define _MT2701_REG_H_ -#include -#include -#include -#include -#include -#include -#include "mt2701-afe-common.h" - -/***************************************************************************** - * R E G I S T E R D E F I N I T I O N - *****************************************************************************/ #define AUDIO_TOP_CON0 0x0000 #define AUDIO_TOP_CON4 0x0010 #define AUDIO_TOP_CON5 0x0014 @@ -109,18 +98,6 @@ #define AFE_DAI_BASE 0x1370 #define AFE_DAI_CUR 0x137c -/* AUDIO_TOP_CON0 (0x0000) */ -#define AUDIO_TOP_CON0_A1SYS_A2SYS_ON (0x3 << 0) -#define AUDIO_TOP_CON0_PDN_AFE (0x1 << 2) -#define AUDIO_TOP_CON0_PDN_APLL_CK (0x1 << 23) - -/* AUDIO_TOP_CON4 (0x0010) */ -#define AUDIO_TOP_CON4_I2SO1_PWN (0x1 << 6) -#define AUDIO_TOP_CON4_PDN_A1SYS (0x1 << 21) -#define AUDIO_TOP_CON4_PDN_A2SYS (0x1 << 22) -#define AUDIO_TOP_CON4_PDN_AFE_CONN (0x1 << 23) -#define AUDIO_TOP_CON4_PDN_MRGIF (0x1 << 25) - /* AFE_DAIBT_CON0 (0x001c) */ #define AFE_DAIBT_CON0_DAIBT_EN (0x1 << 0) #define AFE_DAIBT_CON0_BT_FUNC_EN (0x1 << 1) @@ -137,22 +114,8 @@ #define AFE_MRGIF_CON_I2S_MODE_MASK (0xf << 20) #define AFE_MRGIF_CON_I2S_MODE_32K (0x4 << 20) -/* ASYS_I2SO1_CON (0x061c) */ -#define ASYS_I2SO1_CON_FS (0x1f << 8) -#define ASYS_I2SO1_CON_FS_SET(x) ((x) << 8) -#define ASYS_I2SO1_CON_MULTI_CH (0x1 << 16) -#define ASYS_I2SO1_CON_SIDEGEN (0x1 << 30) -#define ASYS_I2SO1_CON_I2S_EN (0x1 << 0) -/* 0:EIAJ 1:I2S */ -#define ASYS_I2SO1_CON_I2S_MODE (0x1 << 3) -#define ASYS_I2SO1_CON_WIDE_MODE (0x1 << 1) -#define ASYS_I2SO1_CON_WIDE_MODE_SET(x) ((x) << 1) - -/* PWR2_TOP_CON (0x0634) */ -#define PWR2_TOP_CON_INIT_VAL (0xffe1ffff) - -/* ASYS_IRQ_CLR (0x07c0) */ -#define ASYS_IRQ_CLR_ALL (0xffffffff) +/* ASYS_TOP_CON (0x0600) */ +#define ASYS_TOP_CON_ASYS_TIMING_ON (0x3 << 0) /* PWR2_ASM_CON1 (0x1070) */ #define PWR2_ASM_CON1_INIT_VAL (0x492492) -- cgit v1.2.3 From 20a1ea2222e7cbf96e9bf8579362e971491e6aea Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 3 Jan 2018 16:38:46 +0100 Subject: ASoC: skl: Fix kernel warning due to zero NHTL entry I got the following kernel warning when loading snd-soc-skl module on Dell Latitude 7270 laptop: memremap attempted on mixed range 0x0000000000000000 size: 0x0 WARNING: CPU: 0 PID: 484 at kernel/memremap.c:98 memremap+0x8a/0x180 Call Trace: skl_nhlt_init+0x82/0xf0 [snd_soc_skl] skl_probe+0x2ee/0x7c0 [snd_soc_skl] .... It seems that the machine doesn't support the SKL DSP gives the empty NHLT entry, and it triggers the warning. For avoiding it, let do the zero check before calling memremap(). Cc: Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-nhlt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index d14c50a60289..1ce414d86d8a 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -43,7 +43,8 @@ struct nhlt_acpi_table *skl_nhlt_init(struct device *dev) obj = acpi_evaluate_dsm(handle, &osc_guid, 1, 1, NULL); if (obj && obj->type == ACPI_TYPE_BUFFER) { nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer; - nhlt_table = (struct nhlt_acpi_table *) + if (nhlt_ptr->length) + nhlt_table = (struct nhlt_acpi_table *) memremap(nhlt_ptr->min_addr, nhlt_ptr->length, MEMREMAP_WB); ACPI_FREE(obj); -- cgit v1.2.3 From 0739fdfc0617a86781799d033e8fe758e8e48554 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 2 Jan 2018 19:47:21 +0800 Subject: ASoC: mediatek: update clock related properties of MT2701 AFE Add 'assigned-clocks*' properties which are used to initialize default domain sources of audio system. we could configure different sets of input clocks through DTS now. Hence driver no longer cares about that. Also we change some 'clock-names' to make them more generic so that other chips can reuse gracefully. Signed-off-by: Ryder Lee Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/mt2701-afe-pcm.txt | 207 +++++++++------------ 1 file changed, 91 insertions(+), 116 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt b/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt index 77a57f84bed4..0450baad2813 100644 --- a/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt +++ b/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt @@ -6,51 +6,44 @@ Required properties: - interrupts: should contain AFE and ASYS interrupts - interrupt-names: should be "afe" and "asys" - power-domains: should define the power domain +- clocks: Must contain an entry for each entry in clock-names + See ../clocks/clock-bindings.txt for details - clock-names: should have these clock names: - "infra_sys_audio_clk", "top_audio_mux1_sel", "top_audio_mux2_sel", - "top_audio_mux1_div", - "top_audio_mux2_div", - "top_audio_48k_timing", - "top_audio_44k_timing", - "top_audpll_mux_sel", - "top_apll_sel", - "top_aud1_pll_98M", - "top_aud2_pll_90M", - "top_hadds2_pll_98M", - "top_hadds2_pll_294M", - "top_audpll", - "top_audpll_d4", - "top_audpll_d8", - "top_audpll_d16", - "top_audpll_d24", - "top_audintbus_sel", - "clk_26m", - "top_syspll1_d4", - "top_aud_k1_src_sel", - "top_aud_k2_src_sel", - "top_aud_k3_src_sel", - "top_aud_k4_src_sel", - "top_aud_k5_src_sel", - "top_aud_k6_src_sel", - "top_aud_k1_src_div", - "top_aud_k2_src_div", - "top_aud_k3_src_div", - "top_aud_k4_src_div", - "top_aud_k5_src_div", - "top_aud_k6_src_div", - "top_aud_i2s1_mclk", - "top_aud_i2s2_mclk", - "top_aud_i2s3_mclk", - "top_aud_i2s4_mclk", - "top_aud_i2s5_mclk", - "top_aud_i2s6_mclk", - "top_asm_m_sel", - "top_asm_h_sel", - "top_univpll2_d4", - "top_univpll2_d2", - "top_syspll_d5"; + "i2s0_src_sel", + "i2s1_src_sel", + "i2s2_src_sel", + "i2s3_src_sel", + "i2s0_src_div", + "i2s1_src_div", + "i2s2_src_div", + "i2s3_src_div", + "i2s0_mclk_en", + "i2s1_mclk_en", + "i2s2_mclk_en", + "i2s3_mclk_en", + "i2so0_hop_ck", + "i2so1_hop_ck", + "i2so2_hop_ck", + "i2so3_hop_ck", + "i2si0_hop_ck", + "i2si1_hop_ck", + "i2si2_hop_ck", + "i2si3_hop_ck", + "asrc0_out_ck", + "asrc1_out_ck", + "asrc2_out_ck", + "asrc3_out_ck", + "audio_afe_pd", + "audio_afe_conn_pd", + "audio_a1sys_pd", + "audio_a2sys_pd", + "audio_mrgif_pd"; +- assigned-clocks: list of input clocks and dividers for the audio system. + See ../clocks/clock-bindings.txt for details. +- assigned-clocks-parents: parent of input clocks of assigned clocks. +- assigned-clock-rates: list of clock frequencies of assigned clocks. Example: @@ -62,93 +55,75 @@ Example: ; interrupt-names = "afe", "asys"; power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>; - clocks = <&infracfg CLK_INFRA_AUDIO>, - <&topckgen CLK_TOP_AUD_MUX1_SEL>, + clocks = <&topckgen CLK_TOP_AUD_MUX1_SEL>, <&topckgen CLK_TOP_AUD_MUX2_SEL>, - <&topckgen CLK_TOP_AUD_MUX1_DIV>, - <&topckgen CLK_TOP_AUD_MUX2_DIV>, - <&topckgen CLK_TOP_AUD_48K_TIMING>, - <&topckgen CLK_TOP_AUD_44K_TIMING>, - <&topckgen CLK_TOP_AUDPLL_MUX_SEL>, - <&topckgen CLK_TOP_APLL_SEL>, - <&topckgen CLK_TOP_AUD1PLL_98M>, - <&topckgen CLK_TOP_AUD2PLL_90M>, - <&topckgen CLK_TOP_HADDS2PLL_98M>, - <&topckgen CLK_TOP_HADDS2PLL_294M>, - <&topckgen CLK_TOP_AUDPLL>, - <&topckgen CLK_TOP_AUDPLL_D4>, - <&topckgen CLK_TOP_AUDPLL_D8>, - <&topckgen CLK_TOP_AUDPLL_D16>, - <&topckgen CLK_TOP_AUDPLL_D24>, - <&topckgen CLK_TOP_AUDINTBUS_SEL>, - <&clk26m>, - <&topckgen CLK_TOP_SYSPLL1_D4>, <&topckgen CLK_TOP_AUD_K1_SRC_SEL>, <&topckgen CLK_TOP_AUD_K2_SRC_SEL>, <&topckgen CLK_TOP_AUD_K3_SRC_SEL>, <&topckgen CLK_TOP_AUD_K4_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K5_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K6_SRC_SEL>, <&topckgen CLK_TOP_AUD_K1_SRC_DIV>, <&topckgen CLK_TOP_AUD_K2_SRC_DIV>, <&topckgen CLK_TOP_AUD_K3_SRC_DIV>, <&topckgen CLK_TOP_AUD_K4_SRC_DIV>, - <&topckgen CLK_TOP_AUD_K5_SRC_DIV>, - <&topckgen CLK_TOP_AUD_K6_SRC_DIV>, <&topckgen CLK_TOP_AUD_I2S1_MCLK>, <&topckgen CLK_TOP_AUD_I2S2_MCLK>, <&topckgen CLK_TOP_AUD_I2S3_MCLK>, <&topckgen CLK_TOP_AUD_I2S4_MCLK>, - <&topckgen CLK_TOP_AUD_I2S5_MCLK>, - <&topckgen CLK_TOP_AUD_I2S6_MCLK>, - <&topckgen CLK_TOP_ASM_M_SEL>, - <&topckgen CLK_TOP_ASM_H_SEL>, - <&topckgen CLK_TOP_UNIVPLL2_D4>, - <&topckgen CLK_TOP_UNIVPLL2_D2>, - <&topckgen CLK_TOP_SYSPLL_D5>; + <&audiosys CLK_AUD_I2SO1>, + <&audiosys CLK_AUD_I2SO2>, + <&audiosys CLK_AUD_I2SO3>, + <&audiosys CLK_AUD_I2SO4>, + <&audiosys CLK_AUD_I2SIN1>, + <&audiosys CLK_AUD_I2SIN2>, + <&audiosys CLK_AUD_I2SIN3>, + <&audiosys CLK_AUD_I2SIN4>, + <&audiosys CLK_AUD_ASRCO1>, + <&audiosys CLK_AUD_ASRCO2>, + <&audiosys CLK_AUD_ASRCO3>, + <&audiosys CLK_AUD_ASRCO4>, + <&audiosys CLK_AUD_AFE>, + <&audiosys CLK_AUD_AFE_CONN>, + <&audiosys CLK_AUD_A1SYS>, + <&audiosys CLK_AUD_A2SYS>, + <&audiosys CLK_AUD_AFE_MRGIF>; - clock-names = "infra_sys_audio_clk", - "top_audio_mux1_sel", + clock-names = "top_audio_mux1_sel", "top_audio_mux2_sel", - "top_audio_mux1_div", - "top_audio_mux2_div", - "top_audio_48k_timing", - "top_audio_44k_timing", - "top_audpll_mux_sel", - "top_apll_sel", - "top_aud1_pll_98M", - "top_aud2_pll_90M", - "top_hadds2_pll_98M", - "top_hadds2_pll_294M", - "top_audpll", - "top_audpll_d4", - "top_audpll_d8", - "top_audpll_d16", - "top_audpll_d24", - "top_audintbus_sel", - "clk_26m", - "top_syspll1_d4", - "top_aud_k1_src_sel", - "top_aud_k2_src_sel", - "top_aud_k3_src_sel", - "top_aud_k4_src_sel", - "top_aud_k5_src_sel", - "top_aud_k6_src_sel", - "top_aud_k1_src_div", - "top_aud_k2_src_div", - "top_aud_k3_src_div", - "top_aud_k4_src_div", - "top_aud_k5_src_div", - "top_aud_k6_src_div", - "top_aud_i2s1_mclk", - "top_aud_i2s2_mclk", - "top_aud_i2s3_mclk", - "top_aud_i2s4_mclk", - "top_aud_i2s5_mclk", - "top_aud_i2s6_mclk", - "top_asm_m_sel", - "top_asm_h_sel", - "top_univpll2_d4", - "top_univpll2_d2", - "top_syspll_d5"; + "i2s0_src_sel", + "i2s1_src_sel", + "i2s2_src_sel", + "i2s3_src_sel", + "i2s0_src_div", + "i2s1_src_div", + "i2s2_src_div", + "i2s3_src_div", + "i2s0_mclk_en", + "i2s1_mclk_en", + "i2s2_mclk_en", + "i2s3_mclk_en", + "i2so0_hop_ck", + "i2so1_hop_ck", + "i2so2_hop_ck", + "i2so3_hop_ck", + "i2si0_hop_ck", + "i2si1_hop_ck", + "i2si2_hop_ck", + "i2si3_hop_ck", + "asrc0_out_ck", + "asrc1_out_ck", + "asrc2_out_ck", + "asrc3_out_ck", + "audio_afe_pd", + "audio_afe_conn_pd", + "audio_a1sys_pd", + "audio_a2sys_pd", + "audio_mrgif_pd"; + + assigned-clocks = <&topckgen CLK_TOP_AUD_MUX1_SEL>, + <&topckgen CLK_TOP_AUD_MUX2_SEL>, + <&topckgen CLK_TOP_AUD_MUX1_DIV>, + <&topckgen CLK_TOP_AUD_MUX2_DIV>; + assigned-clock-parents = <&topckgen CLK_TOP_AUD1PLL_98M>, + <&topckgen CLK_TOP_AUD2PLL_90M>; + assigned-clock-rates = <0>, <0>, <49152000>, <45158400>; }; -- cgit v1.2.3 From 2ca69d73bc05a55edb95689d436ce87974a3162e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 22 Dec 2017 05:29:03 +0000 Subject: ASoC: rcar: tidyup simple-card example for CPU node commit a5702e1cb3c ("ASoC: rsnd: Drop unit-addresses without reg properties") modifies simple-card multi CPU nodes. But, naming of "cpu-x" breaks probing. Let's add reg = ; instead of renaming node. Reported-by: Hiroyuki Yokoyama CC: Geert Uytterhoeven Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index b3c28bdcc268..5bed9a595772 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -197,12 +197,17 @@ Ex) [MEM] -> [SRC2] -> [CTU03] -+ sound { + #address-cells = <1>; + #size-cells = <0>; + compatible = "simple-scu-audio-card"; ... - simple-audio-card,cpu-0 { + simple-audio-card,cpu@0 { + reg = <0>; sound-dai = <&rcar_sound 0>; }; - simple-audio-card,cpu-1 { + simple-audio-card,cpu@1 { + reg = <1>; sound-dai = <&rcar_sound 1>; }; simple-audio-card,codec { -- cgit v1.2.3 From bd70b19e9e7e87ad330d820386774f304e74d112 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 3 Jan 2018 13:39:01 +0100 Subject: ASoC: rt5645: change micbias widget type to supply. Register "micbias1" and "micbias2" to supply widgets as modern drivers do. This should not cause any (new) issues for existing users of the codec, since micbias support is broken anyways. Micbias support needs the RT5645_MICBIAS?_POW_CTRL_SEL bits in the RT5645_GEN_CTRL2 register to be updated when enabled/disabled which we currently do not do. The updating of these bits will be fixed in a follow-up commit. Signed-off-by: Bard Liao Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index daf7b73ba415..6f6da0abe220 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -1980,10 +1980,10 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { /* Input Side */ /* micbias */ - SND_SOC_DAPM_MICBIAS("micbias1", RT5645_PWR_ANLG2, - RT5645_PWR_MB1_BIT, 0), - SND_SOC_DAPM_MICBIAS("micbias2", RT5645_PWR_ANLG2, - RT5645_PWR_MB2_BIT, 0), + SND_SOC_DAPM_SUPPLY("micbias1", RT5645_PWR_ANLG2, + RT5645_PWR_MB1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("micbias2", RT5645_PWR_ANLG2, + RT5645_PWR_MB2_BIT, 0, NULL, 0), /* Input Lines */ SND_SOC_DAPM_INPUT("DMIC L1"), SND_SOC_DAPM_INPUT("DMIC R1"), -- cgit v1.2.3 From e61f3f31e5830f027d8eedb742bc48a9b3173699 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 3 Jan 2018 13:39:02 +0100 Subject: ASoC: rt5645: add micbias power control select. We need to set a corresponding control bit before powering micbias up. Signed-off-by: Bard Liao [hdegoede@redhat.com: Remove 2 unused variable declarations] Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 56 +++++++++++++++++++++++++++++++++++++++++++++-- sound/soc/codecs/rt5645.h | 6 +++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 6f6da0abe220..fbaf36aeb587 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -1943,6 +1943,56 @@ static int rt5650_hp_event(struct snd_soc_dapm_widget *w, return 0; } +static int rt5645_set_micbias1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, RT5645_GEN_CTRL2, + RT5645_MICBIAS1_POW_CTRL_SEL_MASK, + RT5645_MICBIAS1_POW_CTRL_SEL_M); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, RT5645_GEN_CTRL2, + RT5645_MICBIAS1_POW_CTRL_SEL_MASK, + RT5645_MICBIAS1_POW_CTRL_SEL_A); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5645_set_micbias2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, RT5645_GEN_CTRL2, + RT5645_MICBIAS2_POW_CTRL_SEL_MASK, + RT5645_MICBIAS2_POW_CTRL_SEL_M); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, RT5645_GEN_CTRL2, + RT5645_MICBIAS2_POW_CTRL_SEL_MASK, + RT5645_MICBIAS2_POW_CTRL_SEL_A); + break; + + default: + return 0; + } + + return 0; +} + static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("LDO2", RT5645_PWR_MIXER, RT5645_PWR_LDO2_BIT, 0, NULL, 0), @@ -1981,9 +2031,11 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { /* Input Side */ /* micbias */ SND_SOC_DAPM_SUPPLY("micbias1", RT5645_PWR_ANLG2, - RT5645_PWR_MB1_BIT, 0, NULL, 0), + RT5645_PWR_MB1_BIT, 0, rt5645_set_micbias1_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("micbias2", RT5645_PWR_ANLG2, - RT5645_PWR_MB2_BIT, 0, NULL, 0), + RT5645_PWR_MB2_BIT, 0, rt5645_set_micbias2_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), /* Input Lines */ SND_SOC_DAPM_INPUT("DMIC L1"), SND_SOC_DAPM_INPUT("DMIC R1"), diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index cfc5f97549eb..940325b28c29 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -2117,6 +2117,12 @@ enum { #define RT5645_RXDC_SRC_STO (0x0 << 7) #define RT5645_RXDC_SRC_MONO (0x1 << 7) #define RT5645_RXDC_SRC_SFT (7) +#define RT5645_MICBIAS1_POW_CTRL_SEL_MASK (0x1 << 5) +#define RT5645_MICBIAS1_POW_CTRL_SEL_A (0x0 << 5) +#define RT5645_MICBIAS1_POW_CTRL_SEL_M (0x1 << 5) +#define RT5645_MICBIAS2_POW_CTRL_SEL_MASK (0x1 << 4) +#define RT5645_MICBIAS2_POW_CTRL_SEL_A (0x0 << 4) +#define RT5645_MICBIAS2_POW_CTRL_SEL_M (0x1 << 4) #define RT5645_RXDP2_SEL_MASK (0x1 << 3) #define RT5645_RXDP2_SEL_IF2 (0x0 << 3) #define RT5645_RXDP2_SEL_ADC (0x1 << 3) -- cgit v1.2.3 From 96365d9fdb2f0d81bfc010298289a8c168931cd0 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Thu, 4 Jan 2018 15:44:07 +0800 Subject: ASoC: mediatek: add some core clocks for MT2701 AFE Add three core clocks for MT2701 AFE. Signed-off-by: Ryder Lee Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c | 30 ++++++++++++++++++++++- sound/soc/mediatek/mt2701/mt2701-afe-common.h | 3 +++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c index 56a057c78c9a..949fc3a1d025 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c @@ -18,8 +18,11 @@ #include "mt2701-afe-clock-ctrl.h" static const char *const base_clks[] = { + [MT2701_INFRA_SYS_AUDIO] = "infra_sys_audio_clk", [MT2701_TOP_AUD_MCLK_SRC0] = "top_audio_mux1_sel", [MT2701_TOP_AUD_MCLK_SRC1] = "top_audio_mux2_sel", + [MT2701_TOP_AUD_A1SYS] = "top_audio_a1sys_hp", + [MT2701_TOP_AUD_A2SYS] = "top_audio_a2sys_hp", [MT2701_AUDSYS_AFE] = "audio_afe_pd", [MT2701_AUDSYS_AFE_CONN] = "audio_afe_conn_pd", [MT2701_AUDSYS_A1SYS] = "audio_a1sys_pd", @@ -169,10 +172,26 @@ static int mt2701_afe_enable_audsys(struct mtk_base_afe *afe) struct mt2701_afe_private *afe_priv = afe->platform_priv; int ret; - ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_AFE]); + /* Enable infra clock gate */ + ret = clk_prepare_enable(afe_priv->base_ck[MT2701_INFRA_SYS_AUDIO]); if (ret) return ret; + /* Enable top a1sys clock gate */ + ret = clk_prepare_enable(afe_priv->base_ck[MT2701_TOP_AUD_A1SYS]); + if (ret) + goto err_a1sys; + + /* Enable top a2sys clock gate */ + ret = clk_prepare_enable(afe_priv->base_ck[MT2701_TOP_AUD_A2SYS]); + if (ret) + goto err_a2sys; + + /* Internal clock gates */ + ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_AFE]); + if (ret) + goto err_afe; + ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]); if (ret) goto err_audio_a1sys; @@ -193,6 +212,12 @@ err_audio_a2sys: clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]); err_audio_a1sys: clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE]); +err_afe: + clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A2SYS]); +err_a2sys: + clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A1SYS]); +err_a1sys: + clk_disable_unprepare(afe_priv->base_ck[MT2701_INFRA_SYS_AUDIO]); return ret; } @@ -205,6 +230,9 @@ static void mt2701_afe_disable_audsys(struct mtk_base_afe *afe) clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]); clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]); clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE]); + clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A1SYS]); + clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A2SYS]); + clk_disable_unprepare(afe_priv->base_ck[MT2701_INFRA_SYS_AUDIO]); } int mt2701_afe_enable_clock(struct mtk_base_afe *afe) diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-common.h b/sound/soc/mediatek/mt2701/mt2701-afe-common.h index 9a2b301a4c21..ae8ddeacfbfe 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-common.h +++ b/sound/soc/mediatek/mt2701/mt2701-afe-common.h @@ -61,8 +61,11 @@ enum { }; enum audio_base_clock { + MT2701_INFRA_SYS_AUDIO, MT2701_TOP_AUD_MCLK_SRC0, MT2701_TOP_AUD_MCLK_SRC1, + MT2701_TOP_AUD_A1SYS, + MT2701_TOP_AUD_A2SYS, MT2701_AUDSYS_AFE, MT2701_AUDSYS_AFE_CONN, MT2701_AUDSYS_A1SYS, -- cgit v1.2.3 From dfa3cbb83e099d5ef9809b67ea3bff3a39dc2f06 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Thu, 4 Jan 2018 15:44:08 +0800 Subject: ASoC: mediatek: modify MT2701 AFE driver to adapt mfd device As the new MFD parent is in place, modify MT2701 AFE driver to adapt it. Signed-off-by: Ryder Lee Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 45 +++++++++++++----------------- sound/soc/mediatek/mt2701/mt2701-reg.h | 1 - 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c index 0edadca12a5e..f0cd08fa5c5d 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -1368,14 +1369,6 @@ static const struct mt2701_i2s_data mt2701_i2s_data[MT2701_I2S_NUM][2] = { }, }; -static const struct regmap_config mt2701_afe_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = AFE_END_ADDR, - .cache_type = REGCACHE_NONE, -}; - static irqreturn_t mt2701_asys_isr(int irq_id, void *dev) { int id; @@ -1414,9 +1407,9 @@ static int mt2701_afe_runtime_resume(struct device *dev) static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) { + struct snd_soc_component *component; struct mtk_base_afe *afe; struct mt2701_afe_private *afe_priv; - struct resource *res; struct device *dev; int i, irq_id, ret; @@ -1446,17 +1439,11 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) return ret; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - afe->base_addr = devm_ioremap_resource(&pdev->dev, res); - - if (IS_ERR(afe->base_addr)) - return PTR_ERR(afe->base_addr); - - afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, - &mt2701_afe_regmap_config); - if (IS_ERR(afe->regmap)) - return PTR_ERR(afe->regmap); + afe->regmap = syscon_node_to_regmap(dev->parent->of_node); + if (!afe->regmap) { + dev_err(dev, "could not get regmap from parent\n"); + return -ENODEV; + } mutex_init(&afe->irq_alloc_lock); @@ -1490,6 +1477,12 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) = &mt2701_i2s_data[i][I2S_IN]; } + component = kzalloc(sizeof(*component), GFP_KERNEL); + if (!component) + return -ENOMEM; + + component->regmap = afe->regmap; + afe->mtk_afe_hardware = &mt2701_afe_hardware; afe->memif_fs = mt2701_memif_fs; afe->irq_fs = mt2701_irq_fs; @@ -1502,7 +1495,7 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) ret = mt2701_init_clock(afe); if (ret) { dev_err(dev, "init clock error\n"); - return ret; + goto err_init_clock; } platform_set_drvdata(pdev, afe); @@ -1521,10 +1514,10 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) goto err_platform; } - ret = snd_soc_register_component(&pdev->dev, - &mt2701_afe_pcm_dai_component, - mt2701_afe_pcm_dais, - ARRAY_SIZE(mt2701_afe_pcm_dais)); + ret = snd_soc_add_component(dev, component, + &mt2701_afe_pcm_dai_component, + mt2701_afe_pcm_dais, + ARRAY_SIZE(mt2701_afe_pcm_dais)); if (ret) { dev_warn(dev, "err_dai_component\n"); goto err_dai_component; @@ -1538,6 +1531,8 @@ err_platform: pm_runtime_put_sync(dev); err_pm_disable: pm_runtime_disable(dev); +err_init_clock: + kfree(component); return ret; } diff --git a/sound/soc/mediatek/mt2701/mt2701-reg.h b/sound/soc/mediatek/mt2701/mt2701-reg.h index f17c76f37b5f..18e676974f22 100644 --- a/sound/soc/mediatek/mt2701/mt2701-reg.h +++ b/sound/soc/mediatek/mt2701/mt2701-reg.h @@ -145,5 +145,4 @@ #define ASYS_I2S_CON_WIDE_MODE_SET(x) ((x) << 1) #define ASYS_I2S_IN_PHASE_FIX (0x1 << 31) -#define AFE_END_ADDR 0x15e0 #endif -- cgit v1.2.3 From 7f12a56367bf526afde7e81820a8c7d97e75ed10 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Thu, 4 Jan 2018 15:44:09 +0800 Subject: ASoC: mediatek: update MT2701 AFE documentation to adapt mfd device As the new MFD parent is in place, modify MT2701 AFE documentation to adapt it. Also add three core clocks in example. Signed-off-by: Ryder Lee Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/mt2701-afe-pcm.txt | 171 +++++++++++---------- 1 file changed, 93 insertions(+), 78 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt b/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt index 0450baad2813..6df87b97f7cb 100644 --- a/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt +++ b/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt @@ -2,15 +2,17 @@ Mediatek AFE PCM controller for mt2701 Required properties: - compatible = "mediatek,mt2701-audio"; -- reg: register location and size - interrupts: should contain AFE and ASYS interrupts - interrupt-names: should be "afe" and "asys" - power-domains: should define the power domain - clocks: Must contain an entry for each entry in clock-names See ../clocks/clock-bindings.txt for details - clock-names: should have these clock names: + "infra_sys_audio_clk", "top_audio_mux1_sel", "top_audio_mux2_sel", + "top_audio_a1sys_hp", + "top_audio_a2sys_hp", "i2s0_src_sel", "i2s1_src_sel", "i2s2_src_sel", @@ -45,85 +47,98 @@ Required properties: - assigned-clocks-parents: parent of input clocks of assigned clocks. - assigned-clock-rates: list of clock frequencies of assigned clocks. +Must be a subnode of MediaTek audsys device tree node. +See ../arm/mediatek/mediatek,audsys.txt for details about the parent node. + Example: - afe: mt2701-afe-pcm@11220000 { - compatible = "mediatek,mt2701-audio"; - reg = <0 0x11220000 0 0x2000>, - <0 0x112A0000 0 0x20000>; - interrupts = , - ; - interrupt-names = "afe", "asys"; - power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>; - clocks = <&topckgen CLK_TOP_AUD_MUX1_SEL>, - <&topckgen CLK_TOP_AUD_MUX2_SEL>, - <&topckgen CLK_TOP_AUD_K1_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K2_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K3_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K4_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K1_SRC_DIV>, - <&topckgen CLK_TOP_AUD_K2_SRC_DIV>, - <&topckgen CLK_TOP_AUD_K3_SRC_DIV>, - <&topckgen CLK_TOP_AUD_K4_SRC_DIV>, - <&topckgen CLK_TOP_AUD_I2S1_MCLK>, - <&topckgen CLK_TOP_AUD_I2S2_MCLK>, - <&topckgen CLK_TOP_AUD_I2S3_MCLK>, - <&topckgen CLK_TOP_AUD_I2S4_MCLK>, - <&audiosys CLK_AUD_I2SO1>, - <&audiosys CLK_AUD_I2SO2>, - <&audiosys CLK_AUD_I2SO3>, - <&audiosys CLK_AUD_I2SO4>, - <&audiosys CLK_AUD_I2SIN1>, - <&audiosys CLK_AUD_I2SIN2>, - <&audiosys CLK_AUD_I2SIN3>, - <&audiosys CLK_AUD_I2SIN4>, - <&audiosys CLK_AUD_ASRCO1>, - <&audiosys CLK_AUD_ASRCO2>, - <&audiosys CLK_AUD_ASRCO3>, - <&audiosys CLK_AUD_ASRCO4>, - <&audiosys CLK_AUD_AFE>, - <&audiosys CLK_AUD_AFE_CONN>, - <&audiosys CLK_AUD_A1SYS>, - <&audiosys CLK_AUD_A2SYS>, - <&audiosys CLK_AUD_AFE_MRGIF>; + audsys: audio-subsystem@11220000 { + compatible = "mediatek,mt2701-audsys", "syscon", "simple-mfd"; + ... + + afe: audio-controller { + compatible = "mediatek,mt2701-audio"; + interrupts = , + ; + interrupt-names = "afe", "asys"; + power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>; + + clocks = <&infracfg CLK_INFRA_AUDIO>, + <&topckgen CLK_TOP_AUD_MUX1_SEL>, + <&topckgen CLK_TOP_AUD_MUX2_SEL>, + <&topckgen CLK_TOP_AUD_48K_TIMING>, + <&topckgen CLK_TOP_AUD_44K_TIMING>, + <&topckgen CLK_TOP_AUD_K1_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K2_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K3_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K4_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K1_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K2_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K3_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K4_SRC_DIV>, + <&topckgen CLK_TOP_AUD_I2S1_MCLK>, + <&topckgen CLK_TOP_AUD_I2S2_MCLK>, + <&topckgen CLK_TOP_AUD_I2S3_MCLK>, + <&topckgen CLK_TOP_AUD_I2S4_MCLK>, + <&audsys CLK_AUD_I2SO1>, + <&audsys CLK_AUD_I2SO2>, + <&audsys CLK_AUD_I2SO3>, + <&audsys CLK_AUD_I2SO4>, + <&audsys CLK_AUD_I2SIN1>, + <&audsys CLK_AUD_I2SIN2>, + <&audsys CLK_AUD_I2SIN3>, + <&audsys CLK_AUD_I2SIN4>, + <&audsys CLK_AUD_ASRCO1>, + <&audsys CLK_AUD_ASRCO2>, + <&audsys CLK_AUD_ASRCO3>, + <&audsys CLK_AUD_ASRCO4>, + <&audsys CLK_AUD_AFE>, + <&audsys CLK_AUD_AFE_CONN>, + <&audsys CLK_AUD_A1SYS>, + <&audsys CLK_AUD_A2SYS>, + <&audsys CLK_AUD_AFE_MRGIF>; - clock-names = "top_audio_mux1_sel", - "top_audio_mux2_sel", - "i2s0_src_sel", - "i2s1_src_sel", - "i2s2_src_sel", - "i2s3_src_sel", - "i2s0_src_div", - "i2s1_src_div", - "i2s2_src_div", - "i2s3_src_div", - "i2s0_mclk_en", - "i2s1_mclk_en", - "i2s2_mclk_en", - "i2s3_mclk_en", - "i2so0_hop_ck", - "i2so1_hop_ck", - "i2so2_hop_ck", - "i2so3_hop_ck", - "i2si0_hop_ck", - "i2si1_hop_ck", - "i2si2_hop_ck", - "i2si3_hop_ck", - "asrc0_out_ck", - "asrc1_out_ck", - "asrc2_out_ck", - "asrc3_out_ck", - "audio_afe_pd", - "audio_afe_conn_pd", - "audio_a1sys_pd", - "audio_a2sys_pd", - "audio_mrgif_pd"; + clock-names = "infra_sys_audio_clk", + "top_audio_mux1_sel", + "top_audio_mux2_sel", + "top_audio_a1sys_hp", + "top_audio_a2sys_hp", + "i2s0_src_sel", + "i2s1_src_sel", + "i2s2_src_sel", + "i2s3_src_sel", + "i2s0_src_div", + "i2s1_src_div", + "i2s2_src_div", + "i2s3_src_div", + "i2s0_mclk_en", + "i2s1_mclk_en", + "i2s2_mclk_en", + "i2s3_mclk_en", + "i2so0_hop_ck", + "i2so1_hop_ck", + "i2so2_hop_ck", + "i2so3_hop_ck", + "i2si0_hop_ck", + "i2si1_hop_ck", + "i2si2_hop_ck", + "i2si3_hop_ck", + "asrc0_out_ck", + "asrc1_out_ck", + "asrc2_out_ck", + "asrc3_out_ck", + "audio_afe_pd", + "audio_afe_conn_pd", + "audio_a1sys_pd", + "audio_a2sys_pd", + "audio_mrgif_pd"; - assigned-clocks = <&topckgen CLK_TOP_AUD_MUX1_SEL>, - <&topckgen CLK_TOP_AUD_MUX2_SEL>, - <&topckgen CLK_TOP_AUD_MUX1_DIV>, - <&topckgen CLK_TOP_AUD_MUX2_DIV>; - assigned-clock-parents = <&topckgen CLK_TOP_AUD1PLL_98M>, - <&topckgen CLK_TOP_AUD2PLL_90M>; - assigned-clock-rates = <0>, <0>, <49152000>, <45158400>; + assigned-clocks = <&topckgen CLK_TOP_AUD_MUX1_SEL>, + <&topckgen CLK_TOP_AUD_MUX2_SEL>, + <&topckgen CLK_TOP_AUD_MUX1_DIV>, + <&topckgen CLK_TOP_AUD_MUX2_DIV>; + assigned-clock-parents = <&topckgen CLK_TOP_AUD1PLL_98M>, + <&topckgen CLK_TOP_AUD2PLL_90M>; + assigned-clock-rates = <0>, <0>, <49152000>, <45158400>; + }; }; -- cgit v1.2.3 From bab4a10f0dc745b3c07acb8fa5fbc4337e140f58 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 3 Jan 2018 10:38:24 -0800 Subject: ASoC: Added device tree binding for max98373 amplifier Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/max98373.txt | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/max98373.txt diff --git a/Documentation/devicetree/bindings/sound/max98373.txt b/Documentation/devicetree/bindings/sound/max98373.txt new file mode 100644 index 000000000000..456cb1c59353 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/max98373.txt @@ -0,0 +1,40 @@ +Maxim Integrated MAX98373 Speaker Amplifier + +This device supports I2C. + +Required properties: + + - compatible : "maxim,max98373" + + - reg : the I2C address of the device. + +Optional properties: + + - maxim,vmon-slot-no : slot number used to send voltage information + or in inteleave mode this will be used as + interleave slot. + slot range : 0 ~ 15, Default : 0 + + - maxim,imon-slot-no : slot number used to send current information + slot range : 0 ~ 15, Default : 0 + + - maxim,spkfb-slot-no : slot number used to send speaker feedback information + slot range : 0 ~ 15, Default : 0 + + - maxim,interleave-mode : For cases where a single combined channel + for the I/V sense data is not sufficient, the device can also be configured + to share a single data output channel on alternating frames. + In this configuration, the current and voltage data will be frame interleaved + on a single output channel. + Boolean, define to enable the interleave mode, Default : false + +Example: + +codec: max98373@31 { + compatible = "maxim,max98373"; + reg = <0x31>; + maxim,vmon-slot-no = <0>; + maxim,imon-slot-no = <1>; + maxim,spkfb-slot-no = <2>; + maxim,interleave-mode; +}; -- cgit v1.2.3 From 2f3d24a1355ad32845300dfd0a375c361be7ab38 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 3 Jan 2018 10:39:17 -0800 Subject: ASoC: max98373: Added Amplifier Driver Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/max98373.c | 971 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/max98373.h | 212 ++++++++++ 4 files changed, 1190 insertions(+) create mode 100644 sound/soc/codecs/max98373.c create mode 100644 sound/soc/codecs/max98373.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a42ddbc93f3d..80af1f4d3097 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -95,6 +95,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX98925 if I2C select SND_SOC_MAX98926 if I2C select SND_SOC_MAX98927 if I2C + select SND_SOC_MAX98373 if I2C select SND_SOC_MAX9850 if I2C select SND_SOC_MAX9860 if I2C select SND_SOC_MAX9768 if I2C @@ -623,6 +624,10 @@ config SND_SOC_MAX98927 tristate "Maxim Integrated MAX98927 Speaker Amplifier" depends on I2C +config SND_SOC_MAX98373 + tristate "Maxim Integrated MAX98373 Speaker Amplifier" + depends on I2C + config SND_SOC_MAX9850 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 0001069ce2a7..31a620b5e8a3 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -90,6 +90,7 @@ snd-soc-max9867-objs := max9867.o snd-soc-max98925-objs := max98925.o snd-soc-max98926-objs := max98926.o snd-soc-max98927-objs := max98927.o +snd-soc-max98373-objs := max98373.o snd-soc-max9850-objs := max9850.o snd-soc-max9860-objs := max9860.o snd-soc-mc13783-objs := mc13783.o @@ -330,6 +331,7 @@ obj-$(CONFIG_SND_SOC_MAX9867) += snd-soc-max9867.o obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o obj-$(CONFIG_SND_SOC_MAX98927) += snd-soc-max98927.o +obj-$(CONFIG_SND_SOC_MAX98373) += snd-soc-max98373.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MAX9860) += snd-soc-max9860.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c new file mode 100644 index 000000000000..9af0d985d6e9 --- /dev/null +++ b/sound/soc/codecs/max98373.c @@ -0,0 +1,971 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2017, Maxim Integrated */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "max98373.h" + +static struct reg_default max98373_reg[] = { + {MAX98373_R2000_SW_RESET, 0x00}, + {MAX98373_R2001_INT_RAW1, 0x00}, + {MAX98373_R2002_INT_RAW2, 0x00}, + {MAX98373_R2003_INT_RAW3, 0x00}, + {MAX98373_R2004_INT_STATE1, 0x00}, + {MAX98373_R2005_INT_STATE2, 0x00}, + {MAX98373_R2006_INT_STATE3, 0x00}, + {MAX98373_R2007_INT_FLAG1, 0x00}, + {MAX98373_R2008_INT_FLAG2, 0x00}, + {MAX98373_R2009_INT_FLAG3, 0x00}, + {MAX98373_R200A_INT_EN1, 0x00}, + {MAX98373_R200B_INT_EN2, 0x00}, + {MAX98373_R200C_INT_EN3, 0x00}, + {MAX98373_R200D_INT_FLAG_CLR1, 0x00}, + {MAX98373_R200E_INT_FLAG_CLR2, 0x00}, + {MAX98373_R200F_INT_FLAG_CLR3, 0x00}, + {MAX98373_R2010_IRQ_CTRL, 0x00}, + {MAX98373_R2014_THERM_WARN_THRESH, 0x10}, + {MAX98373_R2015_THERM_SHDN_THRESH, 0x27}, + {MAX98373_R2016_THERM_HYSTERESIS, 0x01}, + {MAX98373_R2017_THERM_FOLDBACK_SET, 0xC0}, + {MAX98373_R2018_THERM_FOLDBACK_EN, 0x00}, + {MAX98373_R201E_PIN_DRIVE_STRENGTH, 0x55}, + {MAX98373_R2020_PCM_TX_HIZ_EN_1, 0xFE}, + {MAX98373_R2021_PCM_TX_HIZ_EN_2, 0xFF}, + {MAX98373_R2022_PCM_TX_SRC_1, 0x00}, + {MAX98373_R2023_PCM_TX_SRC_2, 0x00}, + {MAX98373_R2024_PCM_DATA_FMT_CFG, 0xC0}, + {MAX98373_R2025_AUDIO_IF_MODE, 0x00}, + {MAX98373_R2026_PCM_CLOCK_RATIO, 0x04}, + {MAX98373_R2027_PCM_SR_SETUP_1, 0x08}, + {MAX98373_R2028_PCM_SR_SETUP_2, 0x88}, + {MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1, 0x00}, + {MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2, 0x00}, + {MAX98373_R202B_PCM_RX_EN, 0x00}, + {MAX98373_R202C_PCM_TX_EN, 0x00}, + {MAX98373_R202E_ICC_RX_CH_EN_1, 0x00}, + {MAX98373_R202F_ICC_RX_CH_EN_2, 0x00}, + {MAX98373_R2030_ICC_TX_HIZ_EN_1, 0xFF}, + {MAX98373_R2031_ICC_TX_HIZ_EN_2, 0xFF}, + {MAX98373_R2032_ICC_LINK_EN_CFG, 0x30}, + {MAX98373_R2034_ICC_TX_CNTL, 0x00}, + {MAX98373_R2035_ICC_TX_EN, 0x00}, + {MAX98373_R2036_SOUNDWIRE_CTRL, 0x05}, + {MAX98373_R203D_AMP_DIG_VOL_CTRL, 0x00}, + {MAX98373_R203E_AMP_PATH_GAIN, 0x08}, + {MAX98373_R203F_AMP_DSP_CFG, 0x02}, + {MAX98373_R2040_TONE_GEN_CFG, 0x00}, + {MAX98373_R2041_AMP_CFG, 0x03}, + {MAX98373_R2042_AMP_EDGE_RATE_CFG, 0x00}, + {MAX98373_R2043_AMP_EN, 0x00}, + {MAX98373_R2046_IV_SENSE_ADC_DSP_CFG, 0x04}, + {MAX98373_R2047_IV_SENSE_ADC_EN, 0x00}, + {MAX98373_R2051_MEAS_ADC_SAMPLING_RATE, 0x00}, + {MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG, 0x00}, + {MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG, 0x00}, + {MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0x00}, + {MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0x00}, + {MAX98373_R2056_MEAS_ADC_PVDD_CH_EN, 0x00}, + {MAX98373_R2090_BDE_LVL_HOLD, 0x00}, + {MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 0x00}, + {MAX98373_R2092_BDE_CLIPPER_MODE, 0x00}, + {MAX98373_R2097_BDE_L1_THRESH, 0x00}, + {MAX98373_R2098_BDE_L2_THRESH, 0x00}, + {MAX98373_R2099_BDE_L3_THRESH, 0x00}, + {MAX98373_R209A_BDE_L4_THRESH, 0x00}, + {MAX98373_R209B_BDE_THRESH_HYST, 0x00}, + {MAX98373_R20A8_BDE_L1_CFG_1, 0x00}, + {MAX98373_R20A9_BDE_L1_CFG_2, 0x00}, + {MAX98373_R20AA_BDE_L1_CFG_3, 0x00}, + {MAX98373_R20AB_BDE_L2_CFG_1, 0x00}, + {MAX98373_R20AC_BDE_L2_CFG_2, 0x00}, + {MAX98373_R20AD_BDE_L2_CFG_3, 0x00}, + {MAX98373_R20AE_BDE_L3_CFG_1, 0x00}, + {MAX98373_R20AF_BDE_L3_CFG_2, 0x00}, + {MAX98373_R20B0_BDE_L3_CFG_3, 0x00}, + {MAX98373_R20B1_BDE_L4_CFG_1, 0x00}, + {MAX98373_R20B2_BDE_L4_CFG_2, 0x00}, + {MAX98373_R20B3_BDE_L4_CFG_3, 0x00}, + {MAX98373_R20B4_BDE_INFINITE_HOLD_RELEASE, 0x00}, + {MAX98373_R20B5_BDE_EN, 0x00}, + {MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0x00}, + {MAX98373_R20D1_DHT_CFG, 0x01}, + {MAX98373_R20D2_DHT_ATTACK_CFG, 0x02}, + {MAX98373_R20D3_DHT_RELEASE_CFG, 0x03}, + {MAX98373_R20D4_DHT_EN, 0x00}, + {MAX98373_R20E0_LIMITER_THRESH_CFG, 0x00}, + {MAX98373_R20E1_LIMITER_ATK_REL_RATES, 0x00}, + {MAX98373_R20E2_LIMITER_EN, 0x00}, + {MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG, 0x00}, + {MAX98373_R20FF_GLOBAL_SHDN, 0x00}, + {MAX98373_R21FF_REV_ID, 0x42}, +}; + +static int max98373_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec); + unsigned int format = 0; + unsigned int invert = 0; + + dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt); + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + invert = MAX98373_PCM_MODE_CFG_PCM_BCLKEDGE; + break; + default: + dev_err(codec->dev, "DAI invert mode unsupported\n"); + return -EINVAL; + } + + regmap_update_bits(max98373->regmap, + MAX98373_R2026_PCM_CLOCK_RATIO, + MAX98373_PCM_MODE_CFG_PCM_BCLKEDGE, + invert); + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + format = MAX98373_PCM_FORMAT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + format = MAX98373_PCM_FORMAT_LJ; + break; + case SND_SOC_DAIFMT_DSP_A: + format = MAX98373_PCM_FORMAT_TDM_MODE1; + break; + case SND_SOC_DAIFMT_DSP_B: + format = MAX98373_PCM_FORMAT_TDM_MODE0; + break; + default: + return -EINVAL; + } + + regmap_update_bits(max98373->regmap, + MAX98373_R2024_PCM_DATA_FMT_CFG, + MAX98373_PCM_MODE_CFG_FORMAT_MASK, + format << MAX98373_PCM_MODE_CFG_FORMAT_SHIFT); + + return 0; +} + +/* BCLKs per LRCLK */ +static const int bclk_sel_table[] = { + 32, 48, 64, 96, 128, 192, 256, 384, 512, 320, +}; + +static int max98373_get_bclk_sel(int bclk) +{ + int i; + /* match BCLKs per LRCLK */ + for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) { + if (bclk_sel_table[i] == bclk) + return i + 2; + } + return 0; +} +static int max98373_set_clock(struct snd_soc_codec *codec, + struct snd_pcm_hw_params *params) +{ + struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec); + /* BCLK/LRCLK ratio calculation */ + int blr_clk_ratio = params_channels(params) * max98373->ch_size; + int value; + + if (!max98373->tdm_mode) { + /* BCLK configuration */ + value = max98373_get_bclk_sel(blr_clk_ratio); + if (!value) { + dev_err(codec->dev, "format unsupported %d\n", + params_format(params)); + return -EINVAL; + } + + regmap_update_bits(max98373->regmap, + MAX98373_R2026_PCM_CLOCK_RATIO, + MAX98373_PCM_CLK_SETUP_BSEL_MASK, + value); + } + return 0; +} + +static int max98373_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec); + unsigned int sampling_rate = 0; + unsigned int chan_sz = 0; + + /* pcm mode configuration */ + switch (snd_pcm_format_width(params_format(params))) { + case 16: + chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_16; + break; + case 24: + chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_24; + break; + case 32: + chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_32; + break; + default: + dev_err(codec->dev, "format unsupported %d\n", + params_format(params)); + goto err; + } + + max98373->ch_size = snd_pcm_format_width(params_format(params)); + + regmap_update_bits(max98373->regmap, + MAX98373_R2024_PCM_DATA_FMT_CFG, + MAX98373_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); + + dev_dbg(codec->dev, "format supported %d", + params_format(params)); + + /* sampling rate configuration */ + switch (params_rate(params)) { + case 8000: + sampling_rate = MAX98373_PCM_SR_SET1_SR_8000; + break; + case 11025: + sampling_rate = MAX98373_PCM_SR_SET1_SR_11025; + break; + case 12000: + sampling_rate = MAX98373_PCM_SR_SET1_SR_12000; + break; + case 16000: + sampling_rate = MAX98373_PCM_SR_SET1_SR_16000; + break; + case 22050: + sampling_rate = MAX98373_PCM_SR_SET1_SR_22050; + break; + case 24000: + sampling_rate = MAX98373_PCM_SR_SET1_SR_24000; + break; + case 32000: + sampling_rate = MAX98373_PCM_SR_SET1_SR_32000; + break; + case 44100: + sampling_rate = MAX98373_PCM_SR_SET1_SR_44100; + break; + case 48000: + sampling_rate = MAX98373_PCM_SR_SET1_SR_48000; + break; + default: + dev_err(codec->dev, "rate %d not supported\n", + params_rate(params)); + goto err; + } + /* set DAI_SR to correct LRCLK frequency */ + regmap_update_bits(max98373->regmap, + MAX98373_R2027_PCM_SR_SETUP_1, + MAX98373_PCM_SR_SET1_SR_MASK, + sampling_rate); + regmap_update_bits(max98373->regmap, + MAX98373_R2028_PCM_SR_SETUP_2, + MAX98373_PCM_SR_SET2_SR_MASK, + sampling_rate << MAX98373_PCM_SR_SET2_SR_SHIFT); + + /* set sampling rate of IV */ + if (max98373->interleave_mode && + sampling_rate > MAX98373_PCM_SR_SET1_SR_16000) + regmap_update_bits(max98373->regmap, + MAX98373_R2028_PCM_SR_SETUP_2, + MAX98373_PCM_SR_SET2_IVADC_SR_MASK, + sampling_rate - 3); + else + regmap_update_bits(max98373->regmap, + MAX98373_R2028_PCM_SR_SETUP_2, + MAX98373_PCM_SR_SET2_IVADC_SR_MASK, + sampling_rate); + + return max98373_set_clock(codec, params); +err: + return -EINVAL; +} + +static int max98373_dai_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec); + int bsel = 0; + unsigned int chan_sz = 0; + unsigned int mask; + int x, slot_found; + + max98373->tdm_mode = true; + + /* BCLK configuration */ + bsel = max98373_get_bclk_sel(slots * slot_width); + if (bsel == 0) { + dev_err(codec->dev, "BCLK %d not supported\n", + slots * slot_width); + return -EINVAL; + } + + regmap_update_bits(max98373->regmap, + MAX98373_R2026_PCM_CLOCK_RATIO, + MAX98373_PCM_CLK_SETUP_BSEL_MASK, + bsel); + + /* Channel size configuration */ + switch (slot_width) { + case 16: + chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_16; + break; + case 24: + chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_24; + break; + case 32: + chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_32; + break; + default: + dev_err(codec->dev, "format unsupported %d\n", + slot_width); + return -EINVAL; + } + + regmap_update_bits(max98373->regmap, + MAX98373_R2024_PCM_DATA_FMT_CFG, + MAX98373_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); + + /* Rx slot configuration */ + slot_found = 0; + mask = rx_mask; + for (x = 0 ; x < 16 ; x++, mask >>= 1) { + if (mask & 0x1) { + if (slot_found == 0) + regmap_update_bits(max98373->regmap, + MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1, + MAX98373_PCM_TO_SPK_CH0_SRC_MASK, x); + else + regmap_write(max98373->regmap, + MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2, + x); + slot_found++; + if (slot_found > 1) + break; + } + } + + /* Tx slot Hi-Z configuration */ + regmap_write(max98373->regmap, + MAX98373_R2020_PCM_TX_HIZ_EN_1, + ~tx_mask & 0xFF); + regmap_write(max98373->regmap, + MAX98373_R2021_PCM_TX_HIZ_EN_2, + (~tx_mask & 0xFF00) >> 8); + + return 0; +} + +#define MAX98373_RATES SNDRV_PCM_RATE_8000_96000 + +#define MAX98373_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static const struct snd_soc_dai_ops max98373_dai_ops = { + .set_fmt = max98373_dai_set_fmt, + .hw_params = max98373_dai_hw_params, + .set_tdm_slot = max98373_dai_tdm_slot, +}; + +static int max98373_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(max98373->regmap, + MAX98373_R20FF_GLOBAL_SHDN, + MAX98373_GLOBAL_EN_MASK, 1); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(max98373->regmap, + MAX98373_R20FF_GLOBAL_SHDN, + MAX98373_GLOBAL_EN_MASK, 0); + max98373->tdm_mode = 0; + break; + default: + return 0; + } + return 0; +} + +static const char * const max98373_switch_text[] = { + "Left", "Right", "LeftRight"}; + +static const struct soc_enum dai_sel_enum = + SOC_ENUM_SINGLE(MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1, + MAX98373_PCM_TO_SPK_MONOMIX_CFG_SHIFT, + 3, max98373_switch_text); + +static const struct snd_kcontrol_new max98373_dai_controls = + SOC_DAPM_ENUM("DAI Sel", dai_sel_enum); + +static const struct snd_kcontrol_new max98373_vi_control = + SOC_DAPM_SINGLE("Switch", MAX98373_R202C_PCM_TX_EN, 0, 1, 0); + +static const struct snd_kcontrol_new max98373_spkfb_control = + SOC_DAPM_SINGLE("Switch", MAX98373_R2043_AMP_EN, 1, 1, 0); + +static const struct snd_soc_dapm_widget max98373_dapm_widgets[] = { +SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", + MAX98373_R202B_PCM_RX_EN, 0, 0, max98373_dac_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0, + &max98373_dai_controls), +SND_SOC_DAPM_OUTPUT("BE_OUT"), +SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0, + MAX98373_R2047_IV_SENSE_ADC_EN, 0, 0), +SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0, + MAX98373_R2047_IV_SENSE_ADC_EN, 1, 0), +SND_SOC_DAPM_AIF_OUT("Speaker FB Sense", "HiFi Capture", 0, + SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0, + &max98373_vi_control), +SND_SOC_DAPM_SWITCH("SpkFB Sense", SND_SOC_NOPM, 0, 0, + &max98373_spkfb_control), +SND_SOC_DAPM_SIGGEN("VMON"), +SND_SOC_DAPM_SIGGEN("IMON"), +SND_SOC_DAPM_SIGGEN("FBMON"), +}; + +static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, 0, -50, 0); +static const DECLARE_TLV_DB_RANGE(max98373_spk_tlv, + 0, 8, TLV_DB_SCALE_ITEM(0, 50, 0), + 9, 10, TLV_DB_SCALE_ITEM(500, 100, 0), +); +static const DECLARE_TLV_DB_RANGE(max98373_spkgain_max_tlv, + 0, 9, TLV_DB_SCALE_ITEM(800, 100, 0), +); +static const DECLARE_TLV_DB_RANGE(max98373_dht_step_size_tlv, + 0, 1, TLV_DB_SCALE_ITEM(25, 25, 0), + 2, 4, TLV_DB_SCALE_ITEM(100, 100, 0), +); +static const DECLARE_TLV_DB_RANGE(max98373_dht_spkgain_min_tlv, + 0, 9, TLV_DB_SCALE_ITEM(800, 100, 0), +); +static const DECLARE_TLV_DB_RANGE(max98373_dht_rotation_point_tlv, + 0, 1, TLV_DB_SCALE_ITEM(-50, -50, 0), + 2, 7, TLV_DB_SCALE_ITEM(-200, -100, 0), + 8, 9, TLV_DB_SCALE_ITEM(-1000, -200, 0), + 10, 11, TLV_DB_SCALE_ITEM(-1500, -300, 0), + 12, 13, TLV_DB_SCALE_ITEM(-2000, -200, 0), + 14, 15, TLV_DB_SCALE_ITEM(-2500, -500, 0), +); +static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv, + 0, 15, TLV_DB_SCALE_ITEM(0, -100, 0), +); + +static const DECLARE_TLV_DB_RANGE(max98373_bde_gain_tlv, + 0, 60, TLV_DB_SCALE_ITEM(0, -25, 0), +); + +static bool max98373_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98373_R2001_INT_RAW1 ... MAX98373_R200C_INT_EN3: + case MAX98373_R2010_IRQ_CTRL: + case MAX98373_R2014_THERM_WARN_THRESH + ... MAX98373_R2018_THERM_FOLDBACK_EN: + case MAX98373_R201E_PIN_DRIVE_STRENGTH + ... MAX98373_R2036_SOUNDWIRE_CTRL: + case MAX98373_R203D_AMP_DIG_VOL_CTRL ... MAX98373_R2043_AMP_EN: + case MAX98373_R2046_IV_SENSE_ADC_DSP_CFG + ... MAX98373_R2047_IV_SENSE_ADC_EN: + case MAX98373_R2051_MEAS_ADC_SAMPLING_RATE + ... MAX98373_R2056_MEAS_ADC_PVDD_CH_EN: + case MAX98373_R2090_BDE_LVL_HOLD ... MAX98373_R2092_BDE_CLIPPER_MODE: + case MAX98373_R2097_BDE_L1_THRESH + ... MAX98373_R209B_BDE_THRESH_HYST: + case MAX98373_R20A8_BDE_L1_CFG_1 ... MAX98373_R20B3_BDE_L4_CFG_3: + case MAX98373_R20B5_BDE_EN ... MAX98373_R20B6_BDE_CUR_STATE_READBACK: + case MAX98373_R20D1_DHT_CFG ... MAX98373_R20D4_DHT_EN: + case MAX98373_R20E0_LIMITER_THRESH_CFG ... MAX98373_R20E2_LIMITER_EN: + case MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG + ... MAX98373_R20FF_GLOBAL_SHDN: + case MAX98373_R21FF_REV_ID: + return true; + default: + return false; + } +}; + +static bool max98373_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98373_R2000_SW_RESET ... MAX98373_R2009_INT_FLAG3: + case MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK: + case MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK: + case MAX98373_R20B6_BDE_CUR_STATE_READBACK: + case MAX98373_R21FF_REV_ID: + return true; + default: + return false; + } +} + +static const char * const max98373_output_voltage_lvl_text[] = { + "5.43V", "6.09V", "6.83V", "7.67V", "8.60V", + "9.65V", "10.83V", "12.15V", "13.63V", "15.29V" +}; + +static SOC_ENUM_SINGLE_DECL(max98373_out_volt_enum, + MAX98373_R203E_AMP_PATH_GAIN, 0, + max98373_output_voltage_lvl_text); + +static const char * const max98373_dht_attack_rate_text[] = { + "17.5us", "35us", "70us", "140us", + "280us", "560us", "1120us", "2240us" +}; + +static SOC_ENUM_SINGLE_DECL(max98373_dht_attack_rate_enum, + MAX98373_R20D2_DHT_ATTACK_CFG, 0, + max98373_dht_attack_rate_text); + +static const char * const max98373_dht_release_rate_text[] = { + "45ms", "225ms", "450ms", "1150ms", + "2250ms", "3100ms", "4500ms", "6750ms" +}; + +static SOC_ENUM_SINGLE_DECL(max98373_dht_release_rate_enum, + MAX98373_R20D3_DHT_RELEASE_CFG, 0, + max98373_dht_release_rate_text); + +static const char * const max98373_limiter_attack_rate_text[] = { + "10us", "20us", "40us", "80us", + "160us", "320us", "640us", "1.28ms", + "2.56ms", "5.12ms", "10.24ms", "20.48ms", + "40.96ms", "81.92ms", "16.384ms", "32.768ms" +}; + +static SOC_ENUM_SINGLE_DECL(max98373_limiter_attack_rate_enum, + MAX98373_R20E1_LIMITER_ATK_REL_RATES, 4, + max98373_limiter_attack_rate_text); + +static const char * const max98373_limiter_release_rate_text[] = { + "40us", "80us", "160us", "320us", + "640us", "1.28ms", "2.56ms", "5.120ms", + "10.24ms", "20.48ms", "40.96ms", "81.92ms", + "163.84ms", "327.68ms", "655.36ms", "1310.72ms" +}; + +static SOC_ENUM_SINGLE_DECL(max98373_limiter_release_rate_enum, + MAX98373_R20E1_LIMITER_ATK_REL_RATES, 0, + max98373_limiter_release_rate_text); + +static const char * const max98373_ADC_samplerate_text[] = { + "333kHz", "192kHz", "64kHz", "48kHz" +}; + +static SOC_ENUM_SINGLE_DECL(max98373_adc_samplerate_enum, + MAX98373_R2051_MEAS_ADC_SAMPLING_RATE, 0, + max98373_ADC_samplerate_text); + +static const struct snd_kcontrol_new max98373_snd_controls[] = { +SOC_SINGLE("Digital Vol Sel Switch", MAX98373_R203F_AMP_DSP_CFG, + MAX98373_AMP_VOL_SEL_SHIFT, 1, 0), +SOC_SINGLE("Volume Location Switch", MAX98373_R203F_AMP_DSP_CFG, + MAX98373_AMP_VOL_SEL_SHIFT, 1, 0), +SOC_SINGLE("Ramp Up Switch", MAX98373_R203F_AMP_DSP_CFG, + MAX98373_AMP_DSP_CFG_RMP_UP_SHIFT, 1, 0), +SOC_SINGLE("Ramp Down Switch", MAX98373_R203F_AMP_DSP_CFG, + MAX98373_AMP_DSP_CFG_RMP_DN_SHIFT, 1, 0), +SOC_SINGLE("CLK Monitor Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG, + MAX98373_CLOCK_MON_SHIFT, 1, 0), +SOC_SINGLE("Dither Switch", MAX98373_R203F_AMP_DSP_CFG, + MAX98373_AMP_DSP_CFG_DITH_SHIFT, 1, 0), +SOC_SINGLE("DC Blocker Switch", MAX98373_R203F_AMP_DSP_CFG, + MAX98373_AMP_DSP_CFG_DCBLK_SHIFT, 1, 0), +SOC_SINGLE_TLV("Digital Volume", MAX98373_R203D_AMP_DIG_VOL_CTRL, + 0, 0x7F, 0, max98373_digital_tlv), +SOC_SINGLE_TLV("Speaker Volume", MAX98373_R203E_AMP_PATH_GAIN, + MAX98373_SPK_DIGI_GAIN_SHIFT, 10, 0, max98373_spk_tlv), +SOC_SINGLE_TLV("FS Max Volume", MAX98373_R203E_AMP_PATH_GAIN, + MAX98373_FS_GAIN_MAX_SHIFT, 9, 0, max98373_spkgain_max_tlv), +SOC_ENUM("Output Voltage", max98373_out_volt_enum), +/* Dynamic Headroom Tracking */ +SOC_SINGLE("DHT Switch", MAX98373_R20D4_DHT_EN, + MAX98373_DHT_EN_SHIFT, 1, 0), +SOC_SINGLE_TLV("DHT Gain Min", MAX98373_R20D1_DHT_CFG, + MAX98373_DHT_SPK_GAIN_MIN_SHIFT, 9, 0, max98373_dht_spkgain_min_tlv), +SOC_SINGLE_TLV("DHT Rot Pnt", MAX98373_R20D1_DHT_CFG, + MAX98373_DHT_ROT_PNT_SHIFT, 15, 0, max98373_dht_rotation_point_tlv), +SOC_SINGLE_TLV("DHT Attack Step", MAX98373_R20D2_DHT_ATTACK_CFG, + MAX98373_DHT_ATTACK_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv), +SOC_SINGLE_TLV("DHT Release Step", MAX98373_R20D3_DHT_RELEASE_CFG, + MAX98373_DHT_RELEASE_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv), +SOC_ENUM("DHT Attack Rate", max98373_dht_attack_rate_enum), +SOC_ENUM("DHT Release Rate", max98373_dht_release_rate_enum), +/* ADC configuration */ +SOC_SINGLE("ADC PVDD CH Switch", MAX98373_R2056_MEAS_ADC_PVDD_CH_EN, 0, 1, 0), +SOC_SINGLE("ADC PVDD FLT Switch", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG, + MAX98373_FLT_EN_SHIFT, 1, 0), +SOC_SINGLE("ADC TEMP FLT Switch", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG, + MAX98373_FLT_EN_SHIFT, 1, 0), +SOC_SINGLE("ADC PVDD", MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0, 0xFF, 0), +SOC_SINGLE("ADC TEMP", MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0, 0xFF, 0), +SOC_SINGLE("ADC PVDD FLT Coeff", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG, + 0, 0x3, 0), +SOC_SINGLE("ADC TEMP FLT Coeff", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG, + 0, 0x3, 0), +SOC_ENUM("ADC SampleRate", max98373_adc_samplerate_enum), +/* Brownout Detection Engine */ +SOC_SINGLE("BDE Switch", MAX98373_R20B5_BDE_EN, MAX98373_BDE_EN_SHIFT, 1, 0), +SOC_SINGLE("BDE LVL4 Mute Switch", MAX98373_R20B2_BDE_L4_CFG_2, + MAX98373_LVL4_MUTE_EN_SHIFT, 1, 0), +SOC_SINGLE("BDE LVL4 Hold Switch", MAX98373_R20B2_BDE_L4_CFG_2, + MAX98373_LVL4_HOLD_EN_SHIFT, 1, 0), +SOC_SINGLE("BDE LVL1 Thresh", MAX98373_R2097_BDE_L1_THRESH, 0, 0xFF, 0), +SOC_SINGLE("BDE LVL2 Thresh", MAX98373_R2098_BDE_L2_THRESH, 0, 0xFF, 0), +SOC_SINGLE("BDE LVL3 Thresh", MAX98373_R2099_BDE_L3_THRESH, 0, 0xFF, 0), +SOC_SINGLE("BDE LVL4 Thresh", MAX98373_R209A_BDE_L4_THRESH, 0, 0xFF, 0), +SOC_SINGLE("BDE Active Level", MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0, 8, 0), +SOC_SINGLE("BDE Clip Mode Switch", MAX98373_R2092_BDE_CLIPPER_MODE, 0, 1, 0), +SOC_SINGLE("BDE Thresh Hysteresis", MAX98373_R209B_BDE_THRESH_HYST, 0, 0xFF, 0), +SOC_SINGLE("BDE Hold Time", MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0), +SOC_SINGLE("BDE Attack Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 4, 0xF, 0), +SOC_SINGLE("BDE Release Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 0, 0xF, 0), +SOC_SINGLE_TLV("BDE LVL1 Clip Thresh", MAX98373_R20A9_BDE_L1_CFG_2, + 0, 0x3C, 0, max98373_bde_gain_tlv), +SOC_SINGLE_TLV("BDE LVL2 Clip Thresh", MAX98373_R20AC_BDE_L2_CFG_2, + 0, 0x3C, 0, max98373_bde_gain_tlv), +SOC_SINGLE_TLV("BDE LVL3 Clip Thresh", MAX98373_R20AF_BDE_L3_CFG_2, + 0, 0x3C, 0, max98373_bde_gain_tlv), +SOC_SINGLE_TLV("BDE LVL4 Clip Thresh", MAX98373_R20B2_BDE_L4_CFG_2, + 0, 0x3C, 0, max98373_bde_gain_tlv), +SOC_SINGLE_TLV("BDE LVL1 Clip Gain Reduct", MAX98373_R20AA_BDE_L1_CFG_3, + 0, 0x3C, 0, max98373_bde_gain_tlv), +SOC_SINGLE_TLV("BDE LVL2 Clip Gain Reduct", MAX98373_R20AD_BDE_L2_CFG_3, + 0, 0x3C, 0, max98373_bde_gain_tlv), +SOC_SINGLE_TLV("BDE LVL3 Clip Gain Reduct", MAX98373_R20B0_BDE_L3_CFG_3, + 0, 0x3C, 0, max98373_bde_gain_tlv), +SOC_SINGLE_TLV("BDE LVL4 Clip Gain Reduct", MAX98373_R20B3_BDE_L4_CFG_3, + 0, 0x3C, 0, max98373_bde_gain_tlv), +SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh", MAX98373_R20A8_BDE_L1_CFG_1, + 0, 0xF, 0, max98373_limiter_thresh_tlv), +SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh", MAX98373_R20AB_BDE_L2_CFG_1, + 0, 0xF, 0, max98373_limiter_thresh_tlv), +SOC_SINGLE_TLV("BDE LVL3 Limiter Thresh", MAX98373_R20AE_BDE_L3_CFG_1, + 0, 0xF, 0, max98373_limiter_thresh_tlv), +SOC_SINGLE_TLV("BDE LVL4 Limiter Thresh", MAX98373_R20B1_BDE_L4_CFG_1, + 0, 0xF, 0, max98373_limiter_thresh_tlv), +/* Limiter */ +SOC_SINGLE("Limiter Switch", MAX98373_R20E2_LIMITER_EN, + MAX98373_LIMITER_EN_SHIFT, 1, 0), +SOC_SINGLE("Limiter Src Switch", MAX98373_R20E0_LIMITER_THRESH_CFG, + MAX98373_LIMITER_THRESH_SRC_SHIFT, 1, 0), +SOC_SINGLE_TLV("Limiter Thresh", MAX98373_R20E0_LIMITER_THRESH_CFG, + MAX98373_LIMITER_THRESH_SHIFT, 15, 0, max98373_limiter_thresh_tlv), +SOC_ENUM("Limiter Attack Rate", max98373_limiter_attack_rate_enum), +SOC_ENUM("Limiter Release Rate", max98373_limiter_release_rate_enum), +}; + +static const struct snd_soc_dapm_route max98373_audio_map[] = { + /* Plabyack */ + {"DAI Sel Mux", "Left", "Amp Enable"}, + {"DAI Sel Mux", "Right", "Amp Enable"}, + {"DAI Sel Mux", "LeftRight", "Amp Enable"}, + {"BE_OUT", NULL, "DAI Sel Mux"}, + /* Capture */ + { "VI Sense", "Switch", "VMON" }, + { "VI Sense", "Switch", "IMON" }, + { "SpkFB Sense", "Switch", "FBMON" }, + { "Voltage Sense", NULL, "VI Sense" }, + { "Current Sense", NULL, "VI Sense" }, + { "Speaker FB Sense", NULL, "SpkFB Sense" }, +}; + +static struct snd_soc_dai_driver max98373_dai[] = { + { + .name = "max98373-aif1", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MAX98373_RATES, + .formats = MAX98373_FORMATS, + }, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MAX98373_RATES, + .formats = MAX98373_FORMATS, + }, + .ops = &max98373_dai_ops, + } +}; + +static int max98373_probe(struct snd_soc_codec *codec) +{ + struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec); + + codec->control_data = max98373->regmap; + + /* Software Reset */ + regmap_write(max98373->regmap, + MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET); + + /* IV default slot configuration */ + regmap_write(max98373->regmap, + MAX98373_R2020_PCM_TX_HIZ_EN_1, + 0xFF); + regmap_write(max98373->regmap, + MAX98373_R2021_PCM_TX_HIZ_EN_2, + 0xFF); + /* L/R mix configuration */ + regmap_write(max98373->regmap, + MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1, + 0x80); + regmap_write(max98373->regmap, + MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2, + 0x1); + /* Set inital volume (0dB) */ + regmap_write(max98373->regmap, + MAX98373_R203D_AMP_DIG_VOL_CTRL, + 0x00); + regmap_write(max98373->regmap, + MAX98373_R203E_AMP_PATH_GAIN, + 0x00); + /* Enable DC blocker */ + regmap_write(max98373->regmap, + MAX98373_R203F_AMP_DSP_CFG, + 0x3); + /* Enable IMON VMON DC blocker */ + regmap_write(max98373->regmap, + MAX98373_R2046_IV_SENSE_ADC_DSP_CFG, + 0x7); + /* voltage, current slot configuration */ + regmap_write(max98373->regmap, + MAX98373_R2022_PCM_TX_SRC_1, + (max98373->i_slot << MAX98373_PCM_TX_CH_SRC_A_I_SHIFT | + max98373->v_slot) & 0xFF); + if (max98373->v_slot < 8) + regmap_update_bits(max98373->regmap, + MAX98373_R2020_PCM_TX_HIZ_EN_1, + 1 << max98373->v_slot, 0); + else + regmap_update_bits(max98373->regmap, + MAX98373_R2021_PCM_TX_HIZ_EN_2, + 1 << (max98373->v_slot - 8), 0); + + if (max98373->i_slot < 8) + regmap_update_bits(max98373->regmap, + MAX98373_R2020_PCM_TX_HIZ_EN_1, + 1 << max98373->i_slot, 0); + else + regmap_update_bits(max98373->regmap, + MAX98373_R2021_PCM_TX_HIZ_EN_2, + 1 << (max98373->i_slot - 8), 0); + + /* speaker feedback slot configuration */ + regmap_write(max98373->regmap, + MAX98373_R2023_PCM_TX_SRC_2, + max98373->spkfb_slot & 0xFF); + + /* Set interleave mode */ + if (max98373->interleave_mode) + regmap_update_bits(max98373->regmap, + MAX98373_R2024_PCM_DATA_FMT_CFG, + MAX98373_PCM_TX_CH_INTERLEAVE_MASK, + MAX98373_PCM_TX_CH_INTERLEAVE_MASK); + + /* Speaker enable */ + regmap_update_bits(max98373->regmap, + MAX98373_R2043_AMP_EN, + MAX98373_SPK_EN_MASK, 1); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int max98373_suspend(struct device *dev) +{ + struct max98373_priv *max98373 = dev_get_drvdata(dev); + + regcache_cache_only(max98373->regmap, true); + regcache_mark_dirty(max98373->regmap); + return 0; +} +static int max98373_resume(struct device *dev) +{ + struct max98373_priv *max98373 = dev_get_drvdata(dev); + + regmap_write(max98373->regmap, + MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET); + regcache_cache_only(max98373->regmap, false); + regcache_sync(max98373->regmap); + return 0; +} +#endif + +static const struct dev_pm_ops max98373_pm = { + SET_SYSTEM_SLEEP_PM_OPS(max98373_suspend, max98373_resume) +}; + +static const struct snd_soc_codec_driver soc_codec_dev_max98373 = { + .probe = max98373_probe, + .component_driver = { + .controls = max98373_snd_controls, + .num_controls = ARRAY_SIZE(max98373_snd_controls), + .dapm_widgets = max98373_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98373_dapm_widgets), + .dapm_routes = max98373_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98373_audio_map), + }, +}; + +static const struct regmap_config max98373_regmap = { + .reg_bits = 16, + .val_bits = 8, + .max_register = MAX98373_R21FF_REV_ID, + .reg_defaults = max98373_reg, + .num_reg_defaults = ARRAY_SIZE(max98373_reg), + .readable_reg = max98373_readable_register, + .volatile_reg = max98373_volatile_reg, + .cache_type = REGCACHE_RBTREE, +}; + +static void max98373_slot_config(struct i2c_client *i2c, + struct max98373_priv *max98373) +{ + int value; + struct device *dev = &i2c->dev; + + if (!device_property_read_u32(dev, "maxim,vmon-slot-no", &value)) + max98373->v_slot = value & 0xF; + else + max98373->v_slot = 0; + + if (!device_property_read_u32(dev, "maxim,imon-slot-no", &value)) + max98373->i_slot = value & 0xF; + else + max98373->i_slot = 1; + + if (!device_property_read_u32(dev, "maxim,spkfb-slot-no", &value)) + max98373->spkfb_slot = value & 0xF; + else + max98373->spkfb_slot = 2; +} + +static int max98373_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + + int ret = 0; + int reg = 0; + struct max98373_priv *max98373 = NULL; + + max98373 = devm_kzalloc(&i2c->dev, sizeof(*max98373), GFP_KERNEL); + + if (!max98373) { + ret = -ENOMEM; + return ret; + } + i2c_set_clientdata(i2c, max98373); + + /* update interleave mode info */ + if (device_property_read_bool(&i2c->dev, "maxim,interleave_mode")) + max98373->interleave_mode = 1; + else + max98373->interleave_mode = 0; + + + /* regmap initialization */ + max98373->regmap + = devm_regmap_init_i2c(i2c, &max98373_regmap); + if (IS_ERR(max98373->regmap)) { + ret = PTR_ERR(max98373->regmap); + dev_err(&i2c->dev, + "Failed to allocate regmap: %d\n", ret); + return ret; + } + + /* Check Revision ID */ + ret = regmap_read(max98373->regmap, + MAX98373_R21FF_REV_ID, ®); + if (ret < 0) { + dev_err(&i2c->dev, + "Failed to read: 0x%02X\n", MAX98373_R21FF_REV_ID); + return ret; + } + dev_info(&i2c->dev, "MAX98373 revisionID: 0x%02X\n", reg); + + /* voltage/current slot configuration */ + max98373_slot_config(i2c, max98373); + + /* codec registeration */ + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98373, + max98373_dai, ARRAY_SIZE(max98373_dai)); + if (ret < 0) + dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); + + return ret; +} + +static int max98373_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id max98373_i2c_id[] = { + { "max98373", 0}, + { }, +}; + +MODULE_DEVICE_TABLE(i2c, max98373_i2c_id); + +#if defined(CONFIG_OF) +static const struct of_device_id max98373_of_match[] = { + { .compatible = "maxim,max98373", }, + { } +}; +MODULE_DEVICE_TABLE(of, max98373_of_match); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id max98373_acpi_match[] = { + { "MX98373", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, max98373_acpi_match); +#endif + +static struct i2c_driver max98373_i2c_driver = { + .driver = { + .name = "max98373", + .of_match_table = of_match_ptr(max98373_of_match), + .acpi_match_table = ACPI_PTR(max98373_acpi_match), + .pm = &max98373_pm, + }, + .probe = max98373_i2c_probe, + .remove = max98373_i2c_remove, + .id_table = max98373_i2c_id, +}; + +module_i2c_driver(max98373_i2c_driver) + +MODULE_DESCRIPTION("ALSA SoC MAX98373 driver"); +MODULE_AUTHOR("Ryan Lee "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/max98373.h b/sound/soc/codecs/max98373.h new file mode 100644 index 000000000000..d0b359d0cf8c --- /dev/null +++ b/sound/soc/codecs/max98373.h @@ -0,0 +1,212 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2017, Maxim Integrated */ +#ifndef _MAX98373_H +#define _MAX98373_H + +#define MAX98373_R2000_SW_RESET 0x2000 +#define MAX98373_R2001_INT_RAW1 0x2001 +#define MAX98373_R2002_INT_RAW2 0x2002 +#define MAX98373_R2003_INT_RAW3 0x2003 +#define MAX98373_R2004_INT_STATE1 0x2004 +#define MAX98373_R2005_INT_STATE2 0x2005 +#define MAX98373_R2006_INT_STATE3 0x2006 +#define MAX98373_R2007_INT_FLAG1 0x2007 +#define MAX98373_R2008_INT_FLAG2 0x2008 +#define MAX98373_R2009_INT_FLAG3 0x2009 +#define MAX98373_R200A_INT_EN1 0x200A +#define MAX98373_R200B_INT_EN2 0x200B +#define MAX98373_R200C_INT_EN3 0x200C +#define MAX98373_R200D_INT_FLAG_CLR1 0x200D +#define MAX98373_R200E_INT_FLAG_CLR2 0x200E +#define MAX98373_R200F_INT_FLAG_CLR3 0x200F +#define MAX98373_R2010_IRQ_CTRL 0x2010 +#define MAX98373_R2014_THERM_WARN_THRESH 0x2014 +#define MAX98373_R2015_THERM_SHDN_THRESH 0x2015 +#define MAX98373_R2016_THERM_HYSTERESIS 0x2016 +#define MAX98373_R2017_THERM_FOLDBACK_SET 0x2017 +#define MAX98373_R2018_THERM_FOLDBACK_EN 0x2018 +#define MAX98373_R201E_PIN_DRIVE_STRENGTH 0x201E +#define MAX98373_R2020_PCM_TX_HIZ_EN_1 0x2020 +#define MAX98373_R2021_PCM_TX_HIZ_EN_2 0x2021 +#define MAX98373_R2022_PCM_TX_SRC_1 0x2022 +#define MAX98373_R2023_PCM_TX_SRC_2 0x2023 +#define MAX98373_R2024_PCM_DATA_FMT_CFG 0x2024 +#define MAX98373_R2025_AUDIO_IF_MODE 0x2025 +#define MAX98373_R2026_PCM_CLOCK_RATIO 0x2026 +#define MAX98373_R2027_PCM_SR_SETUP_1 0x2027 +#define MAX98373_R2028_PCM_SR_SETUP_2 0x2028 +#define MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1 0x2029 +#define MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2 0x202A +#define MAX98373_R202B_PCM_RX_EN 0x202B +#define MAX98373_R202C_PCM_TX_EN 0x202C +#define MAX98373_R202E_ICC_RX_CH_EN_1 0x202E +#define MAX98373_R202F_ICC_RX_CH_EN_2 0x202F +#define MAX98373_R2030_ICC_TX_HIZ_EN_1 0x2030 +#define MAX98373_R2031_ICC_TX_HIZ_EN_2 0x2031 +#define MAX98373_R2032_ICC_LINK_EN_CFG 0x2032 +#define MAX98373_R2034_ICC_TX_CNTL 0x2034 +#define MAX98373_R2035_ICC_TX_EN 0x2035 +#define MAX98373_R2036_SOUNDWIRE_CTRL 0x2036 +#define MAX98373_R203D_AMP_DIG_VOL_CTRL 0x203D +#define MAX98373_R203E_AMP_PATH_GAIN 0x203E +#define MAX98373_R203F_AMP_DSP_CFG 0x203F +#define MAX98373_R2040_TONE_GEN_CFG 0x2040 +#define MAX98373_R2041_AMP_CFG 0x2041 +#define MAX98373_R2042_AMP_EDGE_RATE_CFG 0x2042 +#define MAX98373_R2043_AMP_EN 0x2043 +#define MAX98373_R2046_IV_SENSE_ADC_DSP_CFG 0x2046 +#define MAX98373_R2047_IV_SENSE_ADC_EN 0x2047 +#define MAX98373_R2051_MEAS_ADC_SAMPLING_RATE 0x2051 +#define MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG 0x2052 +#define MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG 0x2053 +#define MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK 0x2054 +#define MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK 0x2055 +#define MAX98373_R2056_MEAS_ADC_PVDD_CH_EN 0x2056 +#define MAX98373_R2090_BDE_LVL_HOLD 0x2090 +#define MAX98373_R2091_BDE_GAIN_ATK_REL_RATE 0x2091 +#define MAX98373_R2092_BDE_CLIPPER_MODE 0x2092 +#define MAX98373_R2097_BDE_L1_THRESH 0x2097 +#define MAX98373_R2098_BDE_L2_THRESH 0x2098 +#define MAX98373_R2099_BDE_L3_THRESH 0x2099 +#define MAX98373_R209A_BDE_L4_THRESH 0x209A +#define MAX98373_R209B_BDE_THRESH_HYST 0x209B +#define MAX98373_R20A8_BDE_L1_CFG_1 0x20A8 +#define MAX98373_R20A9_BDE_L1_CFG_2 0x20A9 +#define MAX98373_R20AA_BDE_L1_CFG_3 0x20AA +#define MAX98373_R20AB_BDE_L2_CFG_1 0x20AB +#define MAX98373_R20AC_BDE_L2_CFG_2 0x20AC +#define MAX98373_R20AD_BDE_L2_CFG_3 0x20AD +#define MAX98373_R20AE_BDE_L3_CFG_1 0x20AE +#define MAX98373_R20AF_BDE_L3_CFG_2 0x20AF +#define MAX98373_R20B0_BDE_L3_CFG_3 0x20B0 +#define MAX98373_R20B1_BDE_L4_CFG_1 0x20B1 +#define MAX98373_R20B2_BDE_L4_CFG_2 0x20B2 +#define MAX98373_R20B3_BDE_L4_CFG_3 0x20B3 +#define MAX98373_R20B4_BDE_INFINITE_HOLD_RELEASE 0x20B4 +#define MAX98373_R20B5_BDE_EN 0x20B5 +#define MAX98373_R20B6_BDE_CUR_STATE_READBACK 0x20B6 +#define MAX98373_R20D1_DHT_CFG 0x20D1 +#define MAX98373_R20D2_DHT_ATTACK_CFG 0x20D2 +#define MAX98373_R20D3_DHT_RELEASE_CFG 0x20D3 +#define MAX98373_R20D4_DHT_EN 0x20D4 +#define MAX98373_R20E0_LIMITER_THRESH_CFG 0x20E0 +#define MAX98373_R20E1_LIMITER_ATK_REL_RATES 0x20E1 +#define MAX98373_R20E2_LIMITER_EN 0x20E2 +#define MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG 0x20FE +#define MAX98373_R20FF_GLOBAL_SHDN 0x20FF +#define MAX98373_R21FF_REV_ID 0x21FF + +/* MAX98373_R2022_PCM_TX_SRC_1 */ +#define MAX98373_PCM_TX_CH_SRC_A_V_SHIFT (0) +#define MAX98373_PCM_TX_CH_SRC_A_I_SHIFT (4) + +/* MAX98373_R2024_PCM_DATA_FMT_CFG */ +#define MAX98373_PCM_MODE_CFG_FORMAT_MASK (0x7 << 3) +#define MAX98373_PCM_MODE_CFG_FORMAT_SHIFT (3) +#define MAX98373_PCM_TX_CH_INTERLEAVE_MASK (0x1 << 2) +#define MAX98373_PCM_FORMAT_I2S (0x0 << 0) +#define MAX98373_PCM_FORMAT_LJ (0x1 << 0) +#define MAX98373_PCM_FORMAT_TDM_MODE0 (0x3 << 0) +#define MAX98373_PCM_FORMAT_TDM_MODE1 (0x4 << 0) +#define MAX98373_PCM_FORMAT_TDM_MODE2 (0x5 << 0) +#define MAX98373_PCM_MODE_CFG_CHANSZ_MASK (0x3 << 6) +#define MAX98373_PCM_MODE_CFG_CHANSZ_16 (0x1 << 6) +#define MAX98373_PCM_MODE_CFG_CHANSZ_24 (0x2 << 6) +#define MAX98373_PCM_MODE_CFG_CHANSZ_32 (0x3 << 6) + +/* MAX98373_R2026_PCM_CLOCK_RATIO */ +#define MAX98373_PCM_MODE_CFG_PCM_BCLKEDGE (0x1 << 4) +#define MAX98373_PCM_CLK_SETUP_BSEL_MASK (0xF << 0) + +/* MAX98373_R2027_PCM_SR_SETUP_1 */ +#define MAX98373_PCM_SR_SET1_SR_MASK (0xF << 0) +#define MAX98373_PCM_SR_SET1_SR_8000 (0x0 << 0) +#define MAX98373_PCM_SR_SET1_SR_11025 (0x1 << 0) +#define MAX98373_PCM_SR_SET1_SR_12000 (0x2 << 0) +#define MAX98373_PCM_SR_SET1_SR_16000 (0x3 << 0) +#define MAX98373_PCM_SR_SET1_SR_22050 (0x4 << 0) +#define MAX98373_PCM_SR_SET1_SR_24000 (0x5 << 0) +#define MAX98373_PCM_SR_SET1_SR_32000 (0x6 << 0) +#define MAX98373_PCM_SR_SET1_SR_44100 (0x7 << 0) +#define MAX98373_PCM_SR_SET1_SR_48000 (0x8 << 0) + +/* MAX98373_R2028_PCM_SR_SETUP_2 */ +#define MAX98373_PCM_SR_SET2_SR_MASK (0xF << 4) +#define MAX98373_PCM_SR_SET2_SR_SHIFT (4) +#define MAX98373_PCM_SR_SET2_IVADC_SR_MASK (0xF << 0) + +/* MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1 */ +#define MAX98373_PCM_TO_SPK_MONOMIX_CFG_MASK (0x3 << 6) +#define MAX98373_PCM_TO_SPK_MONOMIX_CFG_SHIFT (6) +#define MAX98373_PCM_TO_SPK_CH0_SRC_MASK (0xF << 0) + +/* MAX98373_R203E_AMP_PATH_GAIN */ +#define MAX98373_SPK_DIGI_GAIN_MASK (0xF << 4) +#define MAX98373_SPK_DIGI_GAIN_SHIFT (4) +#define MAX98373_FS_GAIN_MAX_MASK (0xF << 0) +#define MAX98373_FS_GAIN_MAX_SHIFT (0) + +/* MAX98373_R203F_AMP_DSP_CFG */ +#define MAX98373_AMP_DSP_CFG_DCBLK_SHIFT (0) +#define MAX98373_AMP_DSP_CFG_DITH_SHIFT (1) +#define MAX98373_AMP_DSP_CFG_RMP_UP_SHIFT (2) +#define MAX98373_AMP_DSP_CFG_RMP_DN_SHIFT (3) +#define MAX98373_AMP_DSP_CFG_DAC_INV_SHIFT (5) +#define MAX98373_AMP_VOL_SEL_SHIFT (7) + +/* MAX98373_R2043_AMP_EN */ +#define MAX98373_SPKFB_EN_MASK (0x1 << 1) +#define MAX98373_SPK_EN_MASK (0x1 << 0) +#define MAX98373_SPKFB_EN_SHIFT (1) + +/*MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG */ +#define MAX98373_FLT_EN_SHIFT (4) + +/* MAX98373_R20B2_BDE_L4_CFG_2 */ +#define MAX98373_LVL4_MUTE_EN_SHIFT (7) +#define MAX98373_LVL4_HOLD_EN_SHIFT (6) + +/* MAX98373_R20B5_BDE_EN */ +#define MAX98373_BDE_EN_SHIFT (0) + +/* MAX98373_R20D1_DHT_CFG */ +#define MAX98373_DHT_SPK_GAIN_MIN_SHIFT (4) +#define MAX98373_DHT_ROT_PNT_SHIFT (0) + +/* MAX98373_R20D2_DHT_ATTACK_CFG */ +#define MAX98373_DHT_ATTACK_STEP_SHIFT (3) +#define MAX98373_DHT_ATTACK_RATE_SHIFT (0) + +/* MAX98373_R20D3_DHT_RELEASE_CFG */ +#define MAX98373_DHT_RELEASE_STEP_SHIFT (3) +#define MAX98373_DHT_RELEASE_RATE_SHIFT (0) + +/* MAX98373_R20D4_DHT_EN */ +#define MAX98373_DHT_EN_SHIFT (0) + +/* MAX98373_R20E0_LIMITER_THRESH_CFG */ +#define MAX98373_LIMITER_THRESH_SHIFT (2) +#define MAX98373_LIMITER_THRESH_SRC_SHIFT (0) + +/* MAX98373_R20E2_LIMITER_EN */ +#define MAX98373_LIMITER_EN_SHIFT (0) + +/* MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG */ +#define MAX98373_CLOCK_MON_SHIFT (0) + +/* MAX98373_R20FF_GLOBAL_SHDN */ +#define MAX98373_GLOBAL_EN_MASK (0x1 << 0) + +/* MAX98373_R2000_SW_RESET */ +#define MAX98373_SOFT_RESET (0x1 << 0) + +struct max98373_priv { + struct regmap *regmap; + unsigned int v_slot; + unsigned int i_slot; + unsigned int spkfb_slot; + bool interleave_mode; + unsigned int ch_size; + bool tdm_mode; +}; +#endif -- cgit v1.2.3 From ef42e3557f66bd236bfc157c1f02de5abfd01236 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 4 Jan 2018 15:24:57 -0200 Subject: ASoC: simple-card: Pass 'reg' property in the examples Since unit addresses are passed to simple-audio-card,dai-link a corresponding 'reg' property is needed, otherwise dtc complains (when building with W=1) in case someone copies the bindings example into a real dts file: Warning (unit_address_vs_reg): Node /sound-digital/simple-audio-card,dai-link@0 has a unit name, but no reg property Improve the example by passing the correct 'reg' properties. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/simple-card.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt index 166f2290233b..17c13e74667d 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.txt +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -140,6 +140,7 @@ sound { simple-audio-card,name = "Cubox Audio"; simple-audio-card,dai-link@0 { /* I2S - HDMI */ + reg = <0>; format = "i2s"; cpu { sound-dai = <&audio1 0>; @@ -150,6 +151,7 @@ sound { }; simple-audio-card,dai-link@1 { /* S/PDIF - HDMI */ + reg = <1>; cpu { sound-dai = <&audio1 1>; }; @@ -159,6 +161,7 @@ sound { }; simple-audio-card,dai-link@2 { /* S/PDIF - S/PDIF */ + reg = <2>; cpu { sound-dai = <&audio1 1>; }; -- cgit v1.2.3 From d43c17daf2771f703bd92a78b34c7b0f3dcc9576 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 5 Jan 2018 12:18:07 +0200 Subject: ASoC: davinci-mcasp: Add rule to constrain the minimum period size The minimum period size (in frames) must be not lower than the FIFO size of McASP and in general too small period size would easily result underrun in applications as eDMA - the most common DMA servicing McASP have support for limited number of periods. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 804c6f2bcf21..03ba218160ca 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1242,6 +1242,20 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params, return snd_mask_refine(fmt, &nfmt); } +static int davinci_mcasp_hw_rule_min_periodsize( + struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *period_size = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE); + struct snd_interval frames; + + snd_interval_any(&frames); + frames.min = 64; + frames.integer = 1; + + return snd_interval_refine(period_size, &frames); +} + static int davinci_mcasp_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { @@ -1333,6 +1347,11 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, return ret; } + snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + davinci_mcasp_hw_rule_min_periodsize, NULL, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); + return 0; } -- cgit v1.2.3 From ba6c29592545635f7c476cbef0db0c4f39495f23 Mon Sep 17 00:00:00 2001 From: Steven Eckhoff Date: Tue, 19 Dec 2017 14:54:25 -0600 Subject: ASoC: TSCS42xx: Add support for Tempo Semiconductor's TSCS42xx audio CODEC Currently there is no support for TSCS42xx audio CODECs. Add support for TSCS42xx audio CODECs. Reviewed-by: Charles Keepax Acked-by: Philippe Ombredanne Signed-off-by: Steven Eckhoff Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/tscs42xx.txt | 16 + .../devicetree/bindings/vendor-prefixes.txt | 1 + MAINTAINERS | 7 + sound/soc/codecs/Kconfig | 8 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tscs42xx.c | 1456 +++++++++++ sound/soc/codecs/tscs42xx.h | 2693 ++++++++++++++++++++ 7 files changed, 4183 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/tscs42xx.txt create mode 100644 sound/soc/codecs/tscs42xx.c create mode 100644 sound/soc/codecs/tscs42xx.h diff --git a/Documentation/devicetree/bindings/sound/tscs42xx.txt b/Documentation/devicetree/bindings/sound/tscs42xx.txt new file mode 100644 index 000000000000..2ac2f0996697 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tscs42xx.txt @@ -0,0 +1,16 @@ +TSCS42XX Audio CODEC + +Required Properties: + + - compatible : "tempo,tscs42A1" for analog mic + "tempo,tscs42A2" for digital mic + + - reg : <0x71> for analog mic + <0x69> for digital mic + +Example: + +wookie: codec@69 { + compatible = "tempo,tscs42A2"; + reg = <0x69>; +}; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 0994bdd82cd3..f776fb804a8c 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -347,6 +347,7 @@ tcg Trusted Computing Group tcl Toby Churchill Ltd. technexion TechNexion technologic Technologic Systems +tempo Tempo Semiconductor terasic Terasic Inc. thine THine Electronics, Inc. ti Texas Instruments diff --git a/MAINTAINERS b/MAINTAINERS index aa71ab52fd76..8254a90d1cbd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13831,6 +13831,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial.git S: Maintained K: ^Subject:.*(?i)trivial +TEMPO SEMICONDUCTOR DRIVERS +M: Steven Eckhoff +S: Maintained +F: sound/soc/codecs/tscs*.c +F: sound/soc/codecs/tscs*.h +F: Documentation/devicetree/bindings/sound/tscs*.txt + TTY LAYER M: Greg Kroah-Hartman M: Jiri Slaby diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a42ddbc93f3d..fe3bff2f4238 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -158,6 +158,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TLV320AIC3X if I2C select SND_SOC_TPA6130A2 if I2C select SND_SOC_TLV320DAC33 if I2C + select SND_SOC_TSCS42XX if I2C select SND_SOC_TS3A227E if I2C select SND_SOC_TWL4030 if TWL4030_CORE select SND_SOC_TWL6040 if TWL6040_CORE @@ -933,6 +934,13 @@ config SND_SOC_TS3A227E tristate "TI Headset/Mic detect and keypress chip" depends on I2C +config SND_SOC_TSCS42XX + tristate "Tempo Semiconductor TSCS42xx CODEC" + depends on I2C + select REGMAP_I2C + help + Add support for Tempo Semiconductor's TSCS42xx audio CODEC. + config SND_SOC_TWL4030 select MFD_TWL4030_AUDIO tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 0001069ce2a7..ded86bceca37 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -167,6 +167,7 @@ snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o snd-soc-tlv320dac33-objs := tlv320dac33.o +snd-soc-tscs42xx-objs := tscs42xx.o snd-soc-ts3a227e-objs := ts3a227e.o snd-soc-twl4030-objs := twl4030.o snd-soc-twl6040-objs := twl6040.o @@ -406,6 +407,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC32X4_I2C) += snd-soc-tlv320aic32x4-i2c.o obj-$(CONFIG_SND_SOC_TLV320AIC32X4_SPI) += snd-soc-tlv320aic32x4-spi.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o +obj-$(CONFIG_SND_SOC_TSCS42XX) += snd-soc-tscs42xx.o obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c new file mode 100644 index 000000000000..eedd600875e5 --- /dev/null +++ b/sound/soc/codecs/tscs42xx.c @@ -0,0 +1,1456 @@ +// SPDX-License-Identifier: GPL-2.0 +// tscs42xx.c -- TSCS42xx ALSA SoC Audio driver +// Copyright 2017 Tempo Semiconductor, Inc. +// Author: Steven Eckhoff + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tscs42xx.h" + +#define COEFF_SIZE 3 +#define BIQUAD_COEFF_COUNT 5 +#define BIQUAD_SIZE (COEFF_SIZE * BIQUAD_COEFF_COUNT) + +#define COEFF_RAM_MAX_ADDR 0xcd +#define COEFF_RAM_COEFF_COUNT (COEFF_RAM_MAX_ADDR + 1) +#define COEFF_RAM_SIZE (COEFF_SIZE * COEFF_RAM_COEFF_COUNT) + +struct tscs42xx { + + int bclk_ratio; + int samplerate; + unsigned int blrcm; + struct mutex audio_params_lock; + + u8 coeff_ram[COEFF_RAM_SIZE]; + bool coeff_ram_synced; + struct mutex coeff_ram_lock; + + struct mutex pll_lock; + + struct regmap *regmap; + + struct device *dev; +}; + +struct coeff_ram_ctl { + unsigned int addr; + struct soc_bytes_ext bytes_ext; +}; + +static bool tscs42xx_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case R_DACCRWRL: + case R_DACCRWRM: + case R_DACCRWRH: + case R_DACCRRDL: + case R_DACCRRDM: + case R_DACCRRDH: + case R_DACCRSTAT: + case R_DACCRADDR: + case R_PLLCTL0: + return true; + default: + return false; + }; +} + +static bool tscs42xx_precious(struct device *dev, unsigned int reg) +{ + switch (reg) { + case R_DACCRWRL: + case R_DACCRWRM: + case R_DACCRWRH: + case R_DACCRRDL: + case R_DACCRRDM: + case R_DACCRRDH: + return true; + default: + return false; + }; +} + +static const struct regmap_config tscs42xx_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .volatile_reg = tscs42xx_volatile, + .precious_reg = tscs42xx_precious, + .max_register = R_DACMBCREL3H, + + .cache_type = REGCACHE_RBTREE, + .can_multi_write = true, +}; + +#define MAX_PLL_LOCK_20MS_WAITS 1 +static bool plls_locked(struct snd_soc_codec *codec) +{ + int ret; + int count = MAX_PLL_LOCK_20MS_WAITS; + + do { + ret = snd_soc_read(codec, R_PLLCTL0); + if (ret < 0) { + dev_err(codec->dev, + "Failed to read PLL lock status (%d)\n", ret); + return false; + } else if (ret > 0) { + return true; + } + msleep(20); + } while (count--); + + return false; +} + +static int sample_rate_to_pll_freq_out(int sample_rate) +{ + switch (sample_rate) { + case 11025: + case 22050: + case 44100: + case 88200: + return 112896000; + case 8000: + case 16000: + case 32000: + case 48000: + case 96000: + return 122880000; + default: + return -EINVAL; + } +} + +#define DACCRSTAT_MAX_TRYS 10 +static int write_coeff_ram(struct snd_soc_codec *codec, u8 *coeff_ram, + unsigned int addr, unsigned int coeff_cnt) +{ + struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec); + int cnt; + int trys; + int ret; + + for (cnt = 0; cnt < coeff_cnt; cnt++, addr++) { + + for (trys = 0; trys < DACCRSTAT_MAX_TRYS; trys++) { + ret = snd_soc_read(codec, R_DACCRSTAT); + if (ret < 0) { + dev_err(codec->dev, + "Failed to read stat (%d)\n", ret); + return ret; + } + if (!ret) + break; + } + + if (trys == DACCRSTAT_MAX_TRYS) { + ret = -EIO; + dev_err(codec->dev, + "dac coefficient write error (%d)\n", ret); + return ret; + } + + ret = regmap_write(tscs42xx->regmap, R_DACCRADDR, addr); + if (ret < 0) { + dev_err(codec->dev, + "Failed to write dac ram address (%d)\n", ret); + return ret; + } + + ret = regmap_bulk_write(tscs42xx->regmap, R_DACCRWRL, + &coeff_ram[addr * COEFF_SIZE], + COEFF_SIZE); + if (ret < 0) { + dev_err(codec->dev, + "Failed to write dac ram (%d)\n", ret); + return ret; + } + } + + return 0; +} + +static int power_up_audio_plls(struct snd_soc_codec *codec) +{ + struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec); + int freq_out; + int ret; + unsigned int mask; + unsigned int val; + + freq_out = sample_rate_to_pll_freq_out(tscs42xx->samplerate); + switch (freq_out) { + case 122880000: /* 48k */ + mask = RM_PLLCTL1C_PDB_PLL1; + val = RV_PLLCTL1C_PDB_PLL1_ENABLE; + break; + case 112896000: /* 44.1k */ + mask = RM_PLLCTL1C_PDB_PLL2; + val = RV_PLLCTL1C_PDB_PLL2_ENABLE; + break; + default: + ret = -EINVAL; + dev_err(codec->dev, "Unrecognized PLL output freq (%d)\n", ret); + return ret; + } + + mutex_lock(&tscs42xx->pll_lock); + + ret = snd_soc_update_bits(codec, R_PLLCTL1C, mask, val); + if (ret < 0) { + dev_err(codec->dev, "Failed to turn PLL on (%d)\n", ret); + goto exit; + } + + if (!plls_locked(codec)) { + dev_err(codec->dev, "Failed to lock plls\n"); + ret = -ENOMSG; + goto exit; + } + + ret = 0; +exit: + mutex_unlock(&tscs42xx->pll_lock); + + return ret; +} + +static int power_down_audio_plls(struct snd_soc_codec *codec) +{ + struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec); + int ret; + + mutex_lock(&tscs42xx->pll_lock); + + ret = snd_soc_update_bits(codec, R_PLLCTL1C, + RM_PLLCTL1C_PDB_PLL1, + RV_PLLCTL1C_PDB_PLL1_DISABLE); + if (ret < 0) { + dev_err(codec->dev, "Failed to turn PLL off (%d)\n", ret); + goto exit; + } + ret = snd_soc_update_bits(codec, R_PLLCTL1C, + RM_PLLCTL1C_PDB_PLL2, + RV_PLLCTL1C_PDB_PLL2_DISABLE); + if (ret < 0) { + dev_err(codec->dev, "Failed to turn PLL off (%d)\n", ret); + goto exit; + } + + ret = 0; +exit: + mutex_unlock(&tscs42xx->pll_lock); + + return ret; +} + +static int coeff_ram_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec); + struct coeff_ram_ctl *ctl = + (struct coeff_ram_ctl *)kcontrol->private_value; + struct soc_bytes_ext *params = &ctl->bytes_ext; + + mutex_lock(&tscs42xx->coeff_ram_lock); + + memcpy(ucontrol->value.bytes.data, + &tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE], params->max); + + mutex_unlock(&tscs42xx->coeff_ram_lock); + + return 0; +} + +static int coeff_ram_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec); + struct coeff_ram_ctl *ctl = + (struct coeff_ram_ctl *)kcontrol->private_value; + struct soc_bytes_ext *params = &ctl->bytes_ext; + unsigned int coeff_cnt = params->max / COEFF_SIZE; + int ret; + + mutex_lock(&tscs42xx->coeff_ram_lock); + + tscs42xx->coeff_ram_synced = false; + + memcpy(&tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE], + ucontrol->value.bytes.data, params->max); + + mutex_lock(&tscs42xx->pll_lock); + + if (plls_locked(codec)) { + ret = write_coeff_ram(codec, tscs42xx->coeff_ram, + ctl->addr, coeff_cnt); + if (ret < 0) { + dev_err(codec->dev, + "Failed to flush coeff ram cache (%d)\n", ret); + goto exit; + } + tscs42xx->coeff_ram_synced = true; + } + + ret = 0; +exit: + mutex_unlock(&tscs42xx->pll_lock); + + mutex_unlock(&tscs42xx->coeff_ram_lock); + + return ret; +} + +/* Input L Capture Route */ +static char const * const input_select_text[] = { + "Line 1", "Line 2", "Line 3", "D2S" +}; + +static const struct soc_enum left_input_select_enum = +SOC_ENUM_SINGLE(R_INSELL, FB_INSELL, ARRAY_SIZE(input_select_text), + input_select_text); + +static const struct snd_kcontrol_new left_input_select = +SOC_DAPM_ENUM("LEFT_INPUT_SELECT_ENUM", left_input_select_enum); + +/* Input R Capture Route */ +static const struct soc_enum right_input_select_enum = +SOC_ENUM_SINGLE(R_INSELR, FB_INSELR, ARRAY_SIZE(input_select_text), + input_select_text); + +static const struct snd_kcontrol_new right_input_select = +SOC_DAPM_ENUM("RIGHT_INPUT_SELECT_ENUM", right_input_select_enum); + +/* Input Channel Mapping */ +static char const * const ch_map_select_text[] = { + "Normal", "Left to Right", "Right to Left", "Swap" +}; + +static const struct soc_enum ch_map_select_enum = +SOC_ENUM_SINGLE(R_AIC2, FB_AIC2_ADCDSEL, ARRAY_SIZE(ch_map_select_text), + ch_map_select_text); + +static int dapm_vref_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + msleep(20); + return 0; +} + +static int dapm_micb_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + msleep(20); + return 0; +} + +int pll_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + int ret; + + if (SND_SOC_DAPM_EVENT_ON(event)) + ret = power_up_audio_plls(codec); + else + ret = power_down_audio_plls(codec); + + return ret; +} + +int dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec); + int ret; + + mutex_lock(&tscs42xx->coeff_ram_lock); + + if (tscs42xx->coeff_ram_synced == false) { + ret = write_coeff_ram(codec, tscs42xx->coeff_ram, 0x00, + COEFF_RAM_COEFF_COUNT); + if (ret < 0) + goto exit; + tscs42xx->coeff_ram_synced = true; + } + + ret = 0; +exit: + mutex_unlock(&tscs42xx->coeff_ram_lock); + + return ret; +} + +static const struct snd_soc_dapm_widget tscs42xx_dapm_widgets[] = { + /* Vref */ + SND_SOC_DAPM_SUPPLY_S("Vref", 1, R_PWRM2, FB_PWRM2_VREF, 0, + dapm_vref_event, SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), + + /* PLL */ + SND_SOC_DAPM_SUPPLY("PLL", SND_SOC_NOPM, 0, 0, pll_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* Headphone */ + SND_SOC_DAPM_DAC_E("DAC L", "HiFi Playback", R_PWRM2, FB_PWRM2_HPL, 0, + dac_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_DAC_E("DAC R", "HiFi Playback", R_PWRM2, FB_PWRM2_HPR, 0, + dac_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_OUTPUT("Headphone L"), + SND_SOC_DAPM_OUTPUT("Headphone R"), + + /* Speaker */ + SND_SOC_DAPM_DAC_E("ClassD L", "HiFi Playback", + R_PWRM2, FB_PWRM2_SPKL, 0, + dac_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_DAC_E("ClassD R", "HiFi Playback", + R_PWRM2, FB_PWRM2_SPKR, 0, + dac_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_OUTPUT("Speaker L"), + SND_SOC_DAPM_OUTPUT("Speaker R"), + + /* Capture */ + SND_SOC_DAPM_PGA("Analog In PGA L", R_PWRM1, FB_PWRM1_PGAL, 0, NULL, 0), + SND_SOC_DAPM_PGA("Analog In PGA R", R_PWRM1, FB_PWRM1_PGAR, 0, NULL, 0), + SND_SOC_DAPM_PGA("Analog Boost L", R_PWRM1, FB_PWRM1_BSTL, 0, NULL, 0), + SND_SOC_DAPM_PGA("Analog Boost R", R_PWRM1, FB_PWRM1_BSTR, 0, NULL, 0), + SND_SOC_DAPM_PGA("ADC Mute", R_CNVRTR0, FB_CNVRTR0_HPOR, true, NULL, 0), + SND_SOC_DAPM_ADC("ADC L", "HiFi Capture", R_PWRM1, FB_PWRM1_ADCL, 0), + SND_SOC_DAPM_ADC("ADC R", "HiFi Capture", R_PWRM1, FB_PWRM1_ADCR, 0), + + /* Capture Input */ + SND_SOC_DAPM_MUX("Input L Capture Route", R_PWRM2, + FB_PWRM2_INSELL, 0, &left_input_select), + SND_SOC_DAPM_MUX("Input R Capture Route", R_PWRM2, + FB_PWRM2_INSELR, 0, &right_input_select), + + /* Digital Mic */ + SND_SOC_DAPM_SUPPLY_S("Digital Mic Enable", 2, R_DMICCTL, + FB_DMICCTL_DMICEN, 0, NULL, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), + + /* Analog Mic */ + SND_SOC_DAPM_SUPPLY_S("Mic Bias", 2, R_PWRM1, FB_PWRM1_MICB, + 0, dapm_micb_event, SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), + + /* Line In */ + SND_SOC_DAPM_INPUT("Line In 1 L"), + SND_SOC_DAPM_INPUT("Line In 1 R"), + SND_SOC_DAPM_INPUT("Line In 2 L"), + SND_SOC_DAPM_INPUT("Line In 2 R"), + SND_SOC_DAPM_INPUT("Line In 3 L"), + SND_SOC_DAPM_INPUT("Line In 3 R"), +}; + +static const struct snd_soc_dapm_route tscs42xx_intercon[] = { + {"DAC L", NULL, "PLL"}, + {"DAC R", NULL, "PLL"}, + {"DAC L", NULL, "Vref"}, + {"DAC R", NULL, "Vref"}, + {"Headphone L", NULL, "DAC L"}, + {"Headphone R", NULL, "DAC R"}, + + {"ClassD L", NULL, "PLL"}, + {"ClassD R", NULL, "PLL"}, + {"ClassD L", NULL, "Vref"}, + {"ClassD R", NULL, "Vref"}, + {"Speaker L", NULL, "ClassD L"}, + {"Speaker R", NULL, "ClassD R"}, + + {"Input L Capture Route", NULL, "Vref"}, + {"Input R Capture Route", NULL, "Vref"}, + + {"Mic Bias", NULL, "Vref"}, + + {"Input L Capture Route", "Line 1", "Line In 1 L"}, + {"Input R Capture Route", "Line 1", "Line In 1 R"}, + {"Input L Capture Route", "Line 2", "Line In 2 L"}, + {"Input R Capture Route", "Line 2", "Line In 2 R"}, + {"Input L Capture Route", "Line 3", "Line In 3 L"}, + {"Input R Capture Route", "Line 3", "Line In 3 R"}, + + {"Analog In PGA L", NULL, "Input L Capture Route"}, + {"Analog In PGA R", NULL, "Input R Capture Route"}, + {"Analog Boost L", NULL, "Analog In PGA L"}, + {"Analog Boost R", NULL, "Analog In PGA R"}, + {"ADC Mute", NULL, "Analog Boost L"}, + {"ADC Mute", NULL, "Analog Boost R"}, + {"ADC L", NULL, "PLL"}, + {"ADC R", NULL, "PLL"}, + {"ADC L", NULL, "ADC Mute"}, + {"ADC R", NULL, "ADC Mute"}, +}; + +/************ + * CONTROLS * + ************/ + +static char const * const eq_band_enable_text[] = { + "Prescale only", + "Band1", + "Band1:2", + "Band1:3", + "Band1:4", + "Band1:5", + "Band1:6", +}; + +static char const * const level_detection_text[] = { + "Average", + "Peak", +}; + +static char const * const level_detection_window_text[] = { + "512 Samples", + "64 Samples", +}; + +static char const * const compressor_ratio_text[] = { + "Reserved", "1.5:1", "2:1", "3:1", "4:1", "5:1", "6:1", + "7:1", "8:1", "9:1", "10:1", "11:1", "12:1", "13:1", "14:1", + "15:1", "16:1", "17:1", "18:1", "19:1", "20:1", +}; + +static DECLARE_TLV_DB_SCALE(hpvol_scale, -8850, 75, 0); +static DECLARE_TLV_DB_SCALE(spkvol_scale, -7725, 75, 0); +static DECLARE_TLV_DB_SCALE(dacvol_scale, -9563, 38, 0); +static DECLARE_TLV_DB_SCALE(adcvol_scale, -7125, 38, 0); +static DECLARE_TLV_DB_SCALE(invol_scale, -1725, 75, 0); +static DECLARE_TLV_DB_SCALE(mic_boost_scale, 0, 1000, 0); +static DECLARE_TLV_DB_MINMAX(mugain_scale, 0, 4650); +static DECLARE_TLV_DB_MINMAX(compth_scale, -9562, 0); + +static const struct soc_enum eq1_band_enable_enum = + SOC_ENUM_SINGLE(R_CONFIG1, FB_CONFIG1_EQ1_BE, + ARRAY_SIZE(eq_band_enable_text), eq_band_enable_text); + +static const struct soc_enum eq2_band_enable_enum = + SOC_ENUM_SINGLE(R_CONFIG1, FB_CONFIG1_EQ2_BE, + ARRAY_SIZE(eq_band_enable_text), eq_band_enable_text); + +static const struct soc_enum cle_level_detection_enum = + SOC_ENUM_SINGLE(R_CLECTL, FB_CLECTL_LVL_MODE, + ARRAY_SIZE(level_detection_text), + level_detection_text); + +static const struct soc_enum cle_level_detection_window_enum = + SOC_ENUM_SINGLE(R_CLECTL, FB_CLECTL_WINDOWSEL, + ARRAY_SIZE(level_detection_window_text), + level_detection_window_text); + +static const struct soc_enum mbc_level_detection_enums[] = { + SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_LVLMODE1, + ARRAY_SIZE(level_detection_text), + level_detection_text), + SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_LVLMODE2, + ARRAY_SIZE(level_detection_text), + level_detection_text), + SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_LVLMODE3, + ARRAY_SIZE(level_detection_text), + level_detection_text), +}; + +static const struct soc_enum mbc_level_detection_window_enums[] = { + SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_WINSEL1, + ARRAY_SIZE(level_detection_window_text), + level_detection_window_text), + SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_WINSEL2, + ARRAY_SIZE(level_detection_window_text), + level_detection_window_text), + SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_WINSEL3, + ARRAY_SIZE(level_detection_window_text), + level_detection_window_text), +}; + +static const struct soc_enum compressor_ratio_enum = + SOC_ENUM_SINGLE(R_CMPRAT, FB_CMPRAT, + ARRAY_SIZE(compressor_ratio_text), compressor_ratio_text); + +static const struct soc_enum dac_mbc1_compressor_ratio_enum = + SOC_ENUM_SINGLE(R_DACMBCRAT1, FB_DACMBCRAT1_RATIO, + ARRAY_SIZE(compressor_ratio_text), compressor_ratio_text); + +static const struct soc_enum dac_mbc2_compressor_ratio_enum = + SOC_ENUM_SINGLE(R_DACMBCRAT2, FB_DACMBCRAT2_RATIO, + ARRAY_SIZE(compressor_ratio_text), compressor_ratio_text); + +static const struct soc_enum dac_mbc3_compressor_ratio_enum = + SOC_ENUM_SINGLE(R_DACMBCRAT3, FB_DACMBCRAT3_RATIO, + ARRAY_SIZE(compressor_ratio_text), compressor_ratio_text); + +static int bytes_info_ext(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *ucontrol) +{ + struct coeff_ram_ctl *ctl = + (struct coeff_ram_ctl *)kcontrol->private_value; + struct soc_bytes_ext *params = &ctl->bytes_ext; + + ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES; + ucontrol->count = params->max; + + return 0; +} + +#define COEFF_RAM_CTL(xname, xcount, xaddr) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = bytes_info_ext, \ + .get = coeff_ram_get, .put = coeff_ram_put, \ + .private_value = (unsigned long)&(struct coeff_ram_ctl) { \ + .addr = xaddr, \ + .bytes_ext = {.max = xcount, }, \ + } \ +} + +static const struct snd_kcontrol_new tscs42xx_snd_controls[] = { + /* Volumes */ + SOC_DOUBLE_R_TLV("Headphone Playback Volume", R_HPVOLL, R_HPVOLR, + FB_HPVOLL, 0x7F, 0, hpvol_scale), + SOC_DOUBLE_R_TLV("Speaker Playback Volume", R_SPKVOLL, R_SPKVOLR, + FB_SPKVOLL, 0x7F, 0, spkvol_scale), + SOC_DOUBLE_R_TLV("Master Playback Volume", R_DACVOLL, R_DACVOLR, + FB_DACVOLL, 0xFF, 0, dacvol_scale), + SOC_DOUBLE_R_TLV("PCM Capture Volume", R_ADCVOLL, R_ADCVOLR, + FB_ADCVOLL, 0xFF, 0, adcvol_scale), + SOC_DOUBLE_R_TLV("Master Capture Volume", R_INVOLL, R_INVOLR, + FB_INVOLL, 0x3F, 0, invol_scale), + + /* INSEL */ + SOC_DOUBLE_R_TLV("Mic Boost Capture Volume", R_INSELL, R_INSELR, + FB_INSELL_MICBSTL, FV_INSELL_MICBSTL_30DB, + 0, mic_boost_scale), + + /* Input Channel Map */ + SOC_ENUM("Input Channel Map Switch", ch_map_select_enum), + + /* Coefficient Ram */ + COEFF_RAM_CTL("Cascade1L BiQuad1", BIQUAD_SIZE, 0x00), + COEFF_RAM_CTL("Cascade1L BiQuad2", BIQUAD_SIZE, 0x05), + COEFF_RAM_CTL("Cascade1L BiQuad3", BIQUAD_SIZE, 0x0a), + COEFF_RAM_CTL("Cascade1L BiQuad4", BIQUAD_SIZE, 0x0f), + COEFF_RAM_CTL("Cascade1L BiQuad5", BIQUAD_SIZE, 0x14), + COEFF_RAM_CTL("Cascade1L BiQuad6", BIQUAD_SIZE, 0x19), + + COEFF_RAM_CTL("Cascade1R BiQuad1", BIQUAD_SIZE, 0x20), + COEFF_RAM_CTL("Cascade1R BiQuad2", BIQUAD_SIZE, 0x25), + COEFF_RAM_CTL("Cascade1R BiQuad3", BIQUAD_SIZE, 0x2a), + COEFF_RAM_CTL("Cascade1R BiQuad4", BIQUAD_SIZE, 0x2f), + COEFF_RAM_CTL("Cascade1R BiQuad5", BIQUAD_SIZE, 0x34), + COEFF_RAM_CTL("Cascade1R BiQuad6", BIQUAD_SIZE, 0x39), + + COEFF_RAM_CTL("Cascade1L Prescale", COEFF_SIZE, 0x1f), + COEFF_RAM_CTL("Cascade1R Prescale", COEFF_SIZE, 0x3f), + + COEFF_RAM_CTL("Cascade2L BiQuad1", BIQUAD_SIZE, 0x40), + COEFF_RAM_CTL("Cascade2L BiQuad2", BIQUAD_SIZE, 0x45), + COEFF_RAM_CTL("Cascade2L BiQuad3", BIQUAD_SIZE, 0x4a), + COEFF_RAM_CTL("Cascade2L BiQuad4", BIQUAD_SIZE, 0x4f), + COEFF_RAM_CTL("Cascade2L BiQuad5", BIQUAD_SIZE, 0x54), + COEFF_RAM_CTL("Cascade2L BiQuad6", BIQUAD_SIZE, 0x59), + + COEFF_RAM_CTL("Cascade2R BiQuad1", BIQUAD_SIZE, 0x60), + COEFF_RAM_CTL("Cascade2R BiQuad2", BIQUAD_SIZE, 0x65), + COEFF_RAM_CTL("Cascade2R BiQuad3", BIQUAD_SIZE, 0x6a), + COEFF_RAM_CTL("Cascade2R BiQuad4", BIQUAD_SIZE, 0x6f), + COEFF_RAM_CTL("Cascade2R BiQuad5", BIQUAD_SIZE, 0x74), + COEFF_RAM_CTL("Cascade2R BiQuad6", BIQUAD_SIZE, 0x79), + + COEFF_RAM_CTL("Cascade2L Prescale", COEFF_SIZE, 0x5f), + COEFF_RAM_CTL("Cascade2R Prescale", COEFF_SIZE, 0x7f), + + COEFF_RAM_CTL("Bass Extraction BiQuad1", BIQUAD_SIZE, 0x80), + COEFF_RAM_CTL("Bass Extraction BiQuad2", BIQUAD_SIZE, 0x85), + + COEFF_RAM_CTL("Bass Non Linear Function 1", COEFF_SIZE, 0x8a), + COEFF_RAM_CTL("Bass Non Linear Function 2", COEFF_SIZE, 0x8b), + + COEFF_RAM_CTL("Bass Limiter BiQuad", BIQUAD_SIZE, 0x8c), + + COEFF_RAM_CTL("Bass Cut Off BiQuad", BIQUAD_SIZE, 0x91), + + COEFF_RAM_CTL("Bass Mix", COEFF_SIZE, 0x96), + + COEFF_RAM_CTL("Treb Extraction BiQuad1", BIQUAD_SIZE, 0x97), + COEFF_RAM_CTL("Treb Extraction BiQuad2", BIQUAD_SIZE, 0x9c), + + COEFF_RAM_CTL("Treb Non Linear Function 1", COEFF_SIZE, 0xa1), + COEFF_RAM_CTL("Treb Non Linear Function 2", COEFF_SIZE, 0xa2), + + COEFF_RAM_CTL("Treb Limiter BiQuad", BIQUAD_SIZE, 0xa3), + + COEFF_RAM_CTL("Treb Cut Off BiQuad", BIQUAD_SIZE, 0xa8), + + COEFF_RAM_CTL("Treb Mix", COEFF_SIZE, 0xad), + + COEFF_RAM_CTL("3D", COEFF_SIZE, 0xae), + + COEFF_RAM_CTL("3D Mix", COEFF_SIZE, 0xaf), + + COEFF_RAM_CTL("MBC1 BiQuad1", BIQUAD_SIZE, 0xb0), + COEFF_RAM_CTL("MBC1 BiQuad2", BIQUAD_SIZE, 0xb5), + + COEFF_RAM_CTL("MBC2 BiQuad1", BIQUAD_SIZE, 0xba), + COEFF_RAM_CTL("MBC2 BiQuad2", BIQUAD_SIZE, 0xbf), + + COEFF_RAM_CTL("MBC3 BiQuad1", BIQUAD_SIZE, 0xc4), + COEFF_RAM_CTL("MBC3 BiQuad2", BIQUAD_SIZE, 0xc9), + + /* EQ */ + SOC_SINGLE("EQ1 Switch", R_CONFIG1, FB_CONFIG1_EQ1_EN, 1, 0), + SOC_SINGLE("EQ2 Switch", R_CONFIG1, FB_CONFIG1_EQ2_EN, 1, 0), + SOC_ENUM("EQ1 Band Enable Switch", eq1_band_enable_enum), + SOC_ENUM("EQ2 Band Enable Switch", eq2_band_enable_enum), + + /* CLE */ + SOC_ENUM("CLE Level Detect Switch", + cle_level_detection_enum), + SOC_ENUM("CLE Level Detect Win Switch", + cle_level_detection_window_enum), + SOC_SINGLE("Expander Switch", + R_CLECTL, FB_CLECTL_EXP_EN, 1, 0), + SOC_SINGLE("Limiter Switch", + R_CLECTL, FB_CLECTL_LIMIT_EN, 1, 0), + SOC_SINGLE("Comp Switch", + R_CLECTL, FB_CLECTL_COMP_EN, 1, 0), + SOC_SINGLE_TLV("CLE Make-Up Gain Playback Volume", + R_MUGAIN, FB_MUGAIN_CLEMUG, 0x1f, 0, mugain_scale), + SOC_SINGLE_TLV("Comp Thresh Playback Volume", + R_COMPTH, FB_COMPTH, 0xff, 0, compth_scale), + SOC_ENUM("Comp Ratio Switch", compressor_ratio_enum), + SND_SOC_BYTES("Comp Atk Time", R_CATKTCL, 2), + + /* Effects */ + SOC_SINGLE("3D Switch", R_FXCTL, FB_FXCTL_3DEN, 1, 0), + SOC_SINGLE("Treble Switch", R_FXCTL, FB_FXCTL_TEEN, 1, 0), + SOC_SINGLE("Treble Bypass Switch", R_FXCTL, FB_FXCTL_TNLFBYPASS, 1, 0), + SOC_SINGLE("Bass Switch", R_FXCTL, FB_FXCTL_BEEN, 1, 0), + SOC_SINGLE("Bass Bypass Switch", R_FXCTL, FB_FXCTL_BNLFBYPASS, 1, 0), + + /* MBC */ + SOC_SINGLE("MBC Band1 Switch", R_DACMBCEN, FB_DACMBCEN_MBCEN1, 1, 0), + SOC_SINGLE("MBC Band2 Switch", R_DACMBCEN, FB_DACMBCEN_MBCEN2, 1, 0), + SOC_SINGLE("MBC Band3 Switch", R_DACMBCEN, FB_DACMBCEN_MBCEN3, 1, 0), + SOC_ENUM("MBC Band1 Level Detect Switch", + mbc_level_detection_enums[0]), + SOC_ENUM("MBC Band2 Level Detect Switch", + mbc_level_detection_enums[1]), + SOC_ENUM("MBC Band3 Level Detect Switch", + mbc_level_detection_enums[2]), + SOC_ENUM("MBC Band1 Level Detect Win Switch", + mbc_level_detection_window_enums[0]), + SOC_ENUM("MBC Band2 Level Detect Win Switch", + mbc_level_detection_window_enums[1]), + SOC_ENUM("MBC Band3 Level Detect Win Switch", + mbc_level_detection_window_enums[2]), + + SOC_SINGLE("MBC1 Phase Invert", R_DACMBCMUG1, FB_DACMBCMUG1_PHASE, + 1, 0), + SOC_SINGLE_TLV("DAC MBC1 Make-Up Gain Playback Volume", + R_DACMBCMUG1, FB_DACMBCMUG1_MUGAIN, 0x1f, 0, mugain_scale), + SOC_SINGLE_TLV("DAC MBC1 Comp Thresh Playback Volume", + R_DACMBCTHR1, FB_DACMBCTHR1_THRESH, 0xff, 0, compth_scale), + SOC_ENUM("DAC MBC1 Comp Ratio Switch", + dac_mbc1_compressor_ratio_enum), + SND_SOC_BYTES("DAC MBC1 Comp Atk Time", R_DACMBCATK1L, 2), + SND_SOC_BYTES("DAC MBC1 Comp Rel Time Const", + R_DACMBCREL1L, 2), + + SOC_SINGLE("MBC2 Phase Invert", R_DACMBCMUG2, FB_DACMBCMUG2_PHASE, + 1, 0), + SOC_SINGLE_TLV("DAC MBC2 Make-Up Gain Playback Volume", + R_DACMBCMUG2, FB_DACMBCMUG2_MUGAIN, 0x1f, 0, mugain_scale), + SOC_SINGLE_TLV("DAC MBC2 Comp Thresh Playback Volume", + R_DACMBCTHR2, FB_DACMBCTHR2_THRESH, 0xff, 0, compth_scale), + SOC_ENUM("DAC MBC2 Comp Ratio Switch", + dac_mbc2_compressor_ratio_enum), + SND_SOC_BYTES("DAC MBC2 Comp Atk Time", R_DACMBCATK2L, 2), + SND_SOC_BYTES("DAC MBC2 Comp Rel Time Const", + R_DACMBCREL2L, 2), + + SOC_SINGLE("MBC3 Phase Invert", R_DACMBCMUG3, FB_DACMBCMUG3_PHASE, + 1, 0), + SOC_SINGLE_TLV("DAC MBC3 Make-Up Gain Playback Volume", + R_DACMBCMUG3, FB_DACMBCMUG3_MUGAIN, 0x1f, 0, mugain_scale), + SOC_SINGLE_TLV("DAC MBC3 Comp Thresh Playback Volume", + R_DACMBCTHR3, FB_DACMBCTHR3_THRESH, 0xff, 0, compth_scale), + SOC_ENUM("DAC MBC3 Comp Ratio Switch", + dac_mbc3_compressor_ratio_enum), + SND_SOC_BYTES("DAC MBC3 Comp Atk Time", R_DACMBCATK3L, 2), + SND_SOC_BYTES("DAC MBC3 Comp Rel Time Const", + R_DACMBCREL3L, 2), +}; + +static int setup_sample_format(struct snd_soc_codec *codec, + snd_pcm_format_t format) +{ + unsigned int width; + int ret; + + switch (format) { + case SNDRV_PCM_FORMAT_S16_LE: + width = RV_AIC1_WL_16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + width = RV_AIC1_WL_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + width = RV_AIC1_WL_24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + width = RV_AIC1_WL_32; + break; + default: + ret = -EINVAL; + dev_err(codec->dev, "Unsupported format width (%d)\n", ret); + return ret; + } + ret = snd_soc_update_bits(codec, R_AIC1, RM_AIC1_WL, width); + if (ret < 0) { + dev_err(codec->dev, "Failed to set sample width (%d)\n", ret); + return ret; + } + + return 0; +} + +static int setup_sample_rate(struct snd_soc_codec *codec, unsigned int rate) +{ + struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec); + unsigned int br, bm; + int ret; + + switch (rate) { + case 8000: + br = RV_DACSR_DBR_32; + bm = RV_DACSR_DBM_PT25; + break; + case 16000: + br = RV_DACSR_DBR_32; + bm = RV_DACSR_DBM_PT5; + break; + case 24000: + br = RV_DACSR_DBR_48; + bm = RV_DACSR_DBM_PT5; + break; + case 32000: + br = RV_DACSR_DBR_32; + bm = RV_DACSR_DBM_1; + break; + case 48000: + br = RV_DACSR_DBR_48; + bm = RV_DACSR_DBM_1; + break; + case 96000: + br = RV_DACSR_DBR_48; + bm = RV_DACSR_DBM_2; + break; + case 11025: + br = RV_DACSR_DBR_44_1; + bm = RV_DACSR_DBM_PT25; + break; + case 22050: + br = RV_DACSR_DBR_44_1; + bm = RV_DACSR_DBM_PT5; + break; + case 44100: + br = RV_DACSR_DBR_44_1; + bm = RV_DACSR_DBM_1; + break; + case 88200: + br = RV_DACSR_DBR_44_1; + bm = RV_DACSR_DBM_2; + break; + default: + dev_err(codec->dev, "Unsupported sample rate %d\n", rate); + return -EINVAL; + } + + /* DAC and ADC share bit and frame clock */ + ret = snd_soc_update_bits(codec, R_DACSR, RM_DACSR_DBR, br); + if (ret < 0) { + dev_err(codec->dev, "Failed to update register (%d)\n", ret); + return ret; + } + ret = snd_soc_update_bits(codec, R_DACSR, RM_DACSR_DBM, bm); + if (ret < 0) { + dev_err(codec->dev, "Failed to update register (%d)\n", ret); + return ret; + } + ret = snd_soc_update_bits(codec, R_ADCSR, RM_DACSR_DBR, br); + if (ret < 0) { + dev_err(codec->dev, "Failed to update register (%d)\n", ret); + return ret; + } + ret = snd_soc_update_bits(codec, R_ADCSR, RM_DACSR_DBM, bm); + if (ret < 0) { + dev_err(codec->dev, "Failed to update register (%d)\n", ret); + return ret; + } + + mutex_lock(&tscs42xx->audio_params_lock); + + tscs42xx->samplerate = rate; + + mutex_unlock(&tscs42xx->audio_params_lock); + + return 0; +} + +struct reg_setting { + unsigned int addr; + unsigned int val; + unsigned int mask; +}; + +#define PLL_REG_SETTINGS_COUNT 13 +struct pll_ctl { + int input_freq; + struct reg_setting settings[PLL_REG_SETTINGS_COUNT]; +}; + +#define PLL_CTL(f, rt, rd, r1b_l, r9, ra, rb, \ + rc, r12, r1b_h, re, rf, r10, r11) \ + { \ + .input_freq = f, \ + .settings = { \ + {R_TIMEBASE, rt, 0xFF}, \ + {R_PLLCTLD, rd, 0xFF}, \ + {R_PLLCTL1B, r1b_l, 0x0F}, \ + {R_PLLCTL9, r9, 0xFF}, \ + {R_PLLCTLA, ra, 0xFF}, \ + {R_PLLCTLB, rb, 0xFF}, \ + {R_PLLCTLC, rc, 0xFF}, \ + {R_PLLCTL12, r12, 0xFF}, \ + {R_PLLCTL1B, r1b_h, 0xF0}, \ + {R_PLLCTLE, re, 0xFF}, \ + {R_PLLCTLF, rf, 0xFF}, \ + {R_PLLCTL10, r10, 0xFF}, \ + {R_PLLCTL11, r11, 0xFF}, \ + }, \ + } + +static const struct pll_ctl pll_ctls[] = { + PLL_CTL(1411200, 0x05, + 0x39, 0x04, 0x07, 0x02, 0xC3, 0x04, + 0x1B, 0x10, 0x03, 0x03, 0xD0, 0x02), + PLL_CTL(1536000, 0x05, + 0x1A, 0x04, 0x02, 0x03, 0xE0, 0x01, + 0x1A, 0x10, 0x02, 0x03, 0xB9, 0x01), + PLL_CTL(2822400, 0x0A, + 0x23, 0x04, 0x07, 0x04, 0xC3, 0x04, + 0x22, 0x10, 0x05, 0x03, 0x58, 0x02), + PLL_CTL(3072000, 0x0B, + 0x22, 0x04, 0x07, 0x03, 0x48, 0x03, + 0x1A, 0x10, 0x04, 0x03, 0xB9, 0x01), + PLL_CTL(5644800, 0x15, + 0x23, 0x04, 0x0E, 0x04, 0xC3, 0x04, + 0x1A, 0x10, 0x08, 0x03, 0xE0, 0x01), + PLL_CTL(6144000, 0x17, + 0x1A, 0x04, 0x08, 0x03, 0xE0, 0x01, + 0x1A, 0x10, 0x08, 0x03, 0xB9, 0x01), + PLL_CTL(12000000, 0x2E, + 0x1B, 0x04, 0x19, 0x03, 0x00, 0x03, + 0x2A, 0x10, 0x19, 0x05, 0x98, 0x04), + PLL_CTL(19200000, 0x4A, + 0x13, 0x04, 0x14, 0x03, 0x80, 0x01, + 0x1A, 0x10, 0x19, 0x03, 0xB9, 0x01), + PLL_CTL(22000000, 0x55, + 0x2A, 0x04, 0x37, 0x05, 0x00, 0x06, + 0x22, 0x10, 0x26, 0x03, 0x49, 0x02), + PLL_CTL(22579200, 0x57, + 0x22, 0x04, 0x31, 0x03, 0x20, 0x03, + 0x1A, 0x10, 0x1D, 0x03, 0xB3, 0x01), + PLL_CTL(24000000, 0x5D, + 0x13, 0x04, 0x19, 0x03, 0x80, 0x01, + 0x1B, 0x10, 0x19, 0x05, 0x4C, 0x02), + PLL_CTL(24576000, 0x5F, + 0x13, 0x04, 0x1D, 0x03, 0xB3, 0x01, + 0x22, 0x10, 0x40, 0x03, 0x72, 0x03), + PLL_CTL(27000000, 0x68, + 0x22, 0x04, 0x4B, 0x03, 0x00, 0x04, + 0x2A, 0x10, 0x7D, 0x03, 0x20, 0x06), + PLL_CTL(36000000, 0x8C, + 0x1B, 0x04, 0x4B, 0x03, 0x00, 0x03, + 0x2A, 0x10, 0x7D, 0x03, 0x98, 0x04), + PLL_CTL(25000000, 0x61, + 0x1B, 0x04, 0x37, 0x03, 0x2B, 0x03, + 0x1A, 0x10, 0x2A, 0x03, 0x39, 0x02), + PLL_CTL(26000000, 0x65, + 0x23, 0x04, 0x41, 0x05, 0x00, 0x06, + 0x1A, 0x10, 0x26, 0x03, 0xEF, 0x01), + PLL_CTL(12288000, 0x2F, + 0x1A, 0x04, 0x12, 0x03, 0x1C, 0x02, + 0x22, 0x10, 0x20, 0x03, 0x72, 0x03), + PLL_CTL(40000000, 0x9B, + 0x22, 0x08, 0x7D, 0x03, 0x80, 0x04, + 0x23, 0x10, 0x7D, 0x05, 0xE4, 0x06), + PLL_CTL(512000, 0x01, + 0x22, 0x04, 0x01, 0x03, 0xD0, 0x02, + 0x1B, 0x10, 0x01, 0x04, 0x72, 0x03), + PLL_CTL(705600, 0x02, + 0x22, 0x04, 0x02, 0x03, 0x15, 0x04, + 0x22, 0x10, 0x01, 0x04, 0x80, 0x02), + PLL_CTL(1024000, 0x03, + 0x22, 0x04, 0x02, 0x03, 0xD0, 0x02, + 0x1B, 0x10, 0x02, 0x04, 0x72, 0x03), + PLL_CTL(2048000, 0x07, + 0x22, 0x04, 0x04, 0x03, 0xD0, 0x02, + 0x1B, 0x10, 0x04, 0x04, 0x72, 0x03), + PLL_CTL(2400000, 0x08, + 0x22, 0x04, 0x05, 0x03, 0x00, 0x03, + 0x23, 0x10, 0x05, 0x05, 0x98, 0x04), +}; + +static const struct pll_ctl *get_pll_ctl(int input_freq) +{ + int i; + const struct pll_ctl *pll_ctl = NULL; + + for (i = 0; i < ARRAY_SIZE(pll_ctls); ++i) + if (input_freq == pll_ctls[i].input_freq) { + pll_ctl = &pll_ctls[i]; + break; + } + + return pll_ctl; +} + +static int set_pll_ctl_from_input_freq(struct snd_soc_codec *codec, + const int input_freq) +{ + int ret; + int i; + const struct pll_ctl *pll_ctl; + + pll_ctl = get_pll_ctl(input_freq); + if (!pll_ctl) { + ret = -EINVAL; + dev_err(codec->dev, "No PLL input entry for %d (%d)\n", + input_freq, ret); + return ret; + } + + for (i = 0; i < PLL_REG_SETTINGS_COUNT; ++i) { + ret = snd_soc_update_bits(codec, + pll_ctl->settings[i].addr, + pll_ctl->settings[i].mask, + pll_ctl->settings[i].val); + if (ret < 0) { + dev_err(codec->dev, "Failed to set pll ctl (%d)\n", + ret); + return ret; + } + } + + return 0; +} + +static int tscs42xx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int ret; + + ret = setup_sample_format(codec, params_format(params)); + if (ret < 0) { + dev_err(codec->dev, "Failed to setup sample format (%d)\n", + ret); + return ret; + } + + ret = setup_sample_rate(codec, params_rate(params)); + if (ret < 0) { + dev_err(codec->dev, "Failed to setup sample rate (%d)\n", ret); + return ret; + } + + return 0; +} + +static inline int dac_mute(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_update_bits(codec, R_CNVRTR1, RM_CNVRTR1_DACMU, + RV_CNVRTR1_DACMU_ENABLE); + if (ret < 0) { + dev_err(codec->dev, "Failed to mute DAC (%d)\n", + ret); + return ret; + } + + return 0; +} + +static inline int dac_unmute(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_update_bits(codec, R_CNVRTR1, RM_CNVRTR1_DACMU, + RV_CNVRTR1_DACMU_DISABLE); + if (ret < 0) { + dev_err(codec->dev, "Failed to unmute DAC (%d)\n", + ret); + return ret; + } + + return 0; +} + +static inline int adc_mute(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_update_bits(codec, R_CNVRTR0, RM_CNVRTR0_ADCMU, + RV_CNVRTR0_ADCMU_ENABLE); + if (ret < 0) { + dev_err(codec->dev, "Failed to mute ADC (%d)\n", + ret); + return ret; + } + + return 0; +} + +static inline int adc_unmute(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_update_bits(codec, R_CNVRTR0, RM_CNVRTR0_ADCMU, + RV_CNVRTR0_ADCMU_DISABLE); + if (ret < 0) { + dev_err(codec->dev, "Failed to unmute ADC (%d)\n", + ret); + return ret; + } + + return 0; +} + +static int tscs42xx_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_codec *codec = dai->codec; + int ret; + + if (mute) + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + ret = dac_mute(codec); + else + ret = adc_mute(codec); + else + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + ret = dac_unmute(codec); + else + ret = adc_unmute(codec); + + return ret; +} + +static int tscs42xx_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int ret; + + /* Slave mode not supported since it needs always-on frame clock */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + ret = snd_soc_update_bits(codec, R_AIC1, RM_AIC1_MS, + RV_AIC1_MS_MASTER); + if (ret < 0) { + dev_err(codec->dev, + "Failed to set codec DAI master (%d)\n", ret); + return ret; + } + break; + default: + ret = -EINVAL; + dev_err(codec->dev, "Unsupported format (%d)\n", ret); + return ret; + } + + return 0; +} + +static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai, + unsigned int ratio) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec); + unsigned int value; + int ret = 0; + + switch (ratio) { + case 32: + value = RV_DACSR_DBCM_32; + break; + case 40: + value = RV_DACSR_DBCM_40; + break; + case 64: + value = RV_DACSR_DBCM_64; + break; + default: + dev_err(codec->dev, "Unsupported bclk ratio (%d)\n", ret); + return -EINVAL; + } + + ret = snd_soc_update_bits(codec, R_DACSR, RM_DACSR_DBCM, value); + if (ret < 0) { + dev_err(codec->dev, "Failed to set DAC BCLK ratio (%d)\n", ret); + return ret; + } + ret = snd_soc_update_bits(codec, R_ADCSR, RM_ADCSR_ABCM, value); + if (ret < 0) { + dev_err(codec->dev, "Failed to set ADC BCLK ratio (%d)\n", ret); + return ret; + } + + mutex_lock(&tscs42xx->audio_params_lock); + + tscs42xx->bclk_ratio = ratio; + + mutex_unlock(&tscs42xx->audio_params_lock); + + return 0; +} + +static int tscs42xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int ret; + + switch (clk_id) { + case TSCS42XX_PLL_SRC_XTAL: + case TSCS42XX_PLL_SRC_MCLK1: + ret = snd_soc_write(codec, R_PLLREFSEL, + RV_PLLREFSEL_PLL1_REF_SEL_XTAL_MCLK1 | + RV_PLLREFSEL_PLL2_REF_SEL_XTAL_MCLK1); + if (ret < 0) { + dev_err(codec->dev, + "Failed to set pll reference input (%d)\n", + ret); + return ret; + } + break; + case TSCS42XX_PLL_SRC_MCLK2: + ret = snd_soc_write(codec, R_PLLREFSEL, + RV_PLLREFSEL_PLL1_REF_SEL_MCLK2 | + RV_PLLREFSEL_PLL2_REF_SEL_MCLK2); + if (ret < 0) { + dev_err(codec->dev, + "Failed to set PLL reference (%d)\n", ret); + return ret; + } + break; + default: + dev_err(codec->dev, "pll src is unsupported\n"); + return -EINVAL; + } + + ret = set_pll_ctl_from_input_freq(codec, freq); + if (ret < 0) { + dev_err(codec->dev, + "Failed to setup PLL input freq (%d)\n", ret); + return ret; + } + + return 0; +} + +static const struct snd_soc_dai_ops tscs42xx_dai_ops = { + .hw_params = tscs42xx_hw_params, + .mute_stream = tscs42xx_mute_stream, + .set_fmt = tscs42xx_set_dai_fmt, + .set_bclk_ratio = tscs42xx_set_dai_bclk_ratio, + .set_sysclk = tscs42xx_set_dai_sysclk, +}; + +static int part_is_valid(struct tscs42xx *tscs42xx) +{ + int val; + int ret; + unsigned int reg; + + ret = regmap_read(tscs42xx->regmap, R_DEVIDH, ®); + if (ret < 0) + return ret; + + val = reg << 8; + ret = regmap_read(tscs42xx->regmap, R_DEVIDL, ®); + if (ret < 0) + return ret; + + val |= reg; + + switch (val) { + case 0x4A74: + case 0x4A73: + return true; + default: + return false; + }; +} + +static struct snd_soc_codec_driver soc_codec_dev_tscs42xx = { + .component_driver = { + .dapm_widgets = tscs42xx_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tscs42xx_dapm_widgets), + .dapm_routes = tscs42xx_intercon, + .num_dapm_routes = ARRAY_SIZE(tscs42xx_intercon), + .controls = tscs42xx_snd_controls, + .num_controls = ARRAY_SIZE(tscs42xx_snd_controls), + }, +}; + +static inline void init_coeff_ram_cache(struct tscs42xx *tscs42xx) +{ + const u8 norm_addrs[] = { 0x00, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1f, + 0x20, 0x25, 0x2a, 0x2f, 0x34, 0x39, 0x3f, 0x40, 0x45, 0x4a, + 0x4f, 0x54, 0x59, 0x5f, 0x60, 0x65, 0x6a, 0x6f, 0x74, 0x79, + 0x7f, 0x80, 0x85, 0x8c, 0x91, 0x96, 0x97, 0x9c, 0xa3, 0xa8, + 0xad, 0xaf, 0xb0, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, }; + u8 *coeff_ram = tscs42xx->coeff_ram; + int i; + + for (i = 0; i < ARRAY_SIZE(norm_addrs); i++) + coeff_ram[((norm_addrs[i] + 1) * COEFF_SIZE) - 1] = 0x40; +} + +#define TSCS42XX_RATES SNDRV_PCM_RATE_8000_96000 + +#define TSCS42XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ + | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver tscs42xx_dai = { + .name = "tscs42xx-HiFi", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 2, + .channels_max = 2, + .rates = TSCS42XX_RATES, + .formats = TSCS42XX_FORMATS,}, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 2, + .channels_max = 2, + .rates = TSCS42XX_RATES, + .formats = TSCS42XX_FORMATS,}, + .ops = &tscs42xx_dai_ops, + .symmetric_rates = 1, + .symmetric_channels = 1, + .symmetric_samplebits = 1, +}; + +static const struct reg_sequence tscs42xx_patch[] = { + { R_AIC2, RV_AIC2_BLRCM_DAC_BCLK_LRCLK_SHARED }, +}; + +static int tscs42xx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct tscs42xx *tscs42xx; + int ret = 0; + + tscs42xx = devm_kzalloc(&i2c->dev, sizeof(*tscs42xx), GFP_KERNEL); + if (!tscs42xx) { + ret = -ENOMEM; + dev_err(&i2c->dev, + "Failed to allocate memory for data (%d)\n", ret); + return ret; + } + i2c_set_clientdata(i2c, tscs42xx); + tscs42xx->dev = &i2c->dev; + + tscs42xx->regmap = devm_regmap_init_i2c(i2c, &tscs42xx_regmap); + if (IS_ERR(tscs42xx->regmap)) { + ret = PTR_ERR(tscs42xx->regmap); + dev_err(tscs42xx->dev, "Failed to allocate regmap (%d)\n", ret); + return ret; + } + + init_coeff_ram_cache(tscs42xx); + + ret = part_is_valid(tscs42xx); + if (ret <= 0) { + dev_err(tscs42xx->dev, "No valid part (%d)\n", ret); + ret = -ENODEV; + return ret; + } + + ret = regmap_write(tscs42xx->regmap, R_RESET, RV_RESET_ENABLE); + if (ret < 0) { + dev_err(tscs42xx->dev, "Failed to reset device (%d)\n", ret); + return ret; + } + + ret = regmap_register_patch(tscs42xx->regmap, tscs42xx_patch, + ARRAY_SIZE(tscs42xx_patch)); + if (ret < 0) { + dev_err(tscs42xx->dev, "Failed to apply patch (%d)\n", ret); + return ret; + } + + mutex_init(&tscs42xx->audio_params_lock); + mutex_init(&tscs42xx->coeff_ram_lock); + mutex_init(&tscs42xx->pll_lock); + + ret = snd_soc_register_codec(tscs42xx->dev, &soc_codec_dev_tscs42xx, + &tscs42xx_dai, 1); + if (ret) { + dev_err(tscs42xx->dev, "Failed to register codec (%d)\n", ret); + return ret; + } + + return 0; +} + +static int tscs42xx_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + + return 0; +} + +static const struct i2c_device_id tscs42xx_i2c_id[] = { + { "tscs42A1", 0 }, + { "tscs42A2", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tscs42xx_i2c_id); + +static const struct of_device_id tscs42xx_of_match[] = { + { .compatible = "tempo,tscs42A1", }, + { .compatible = "tempo,tscs42A2", }, + { } +}; +MODULE_DEVICE_TABLE(of, tscs42xx_of_match); + +static struct i2c_driver tscs42xx_i2c_driver = { + .driver = { + .name = "tscs42xx", + .owner = THIS_MODULE, + .of_match_table = tscs42xx_of_match, + }, + .probe = tscs42xx_i2c_probe, + .remove = tscs42xx_i2c_remove, + .id_table = tscs42xx_i2c_id, +}; + +module_i2c_driver(tscs42xx_i2c_driver); + +MODULE_AUTHOR("Tempo Semiconductor + +#ifndef __WOOKIE_H__ +#define __WOOKIE_H__ + +enum { + TSCS42XX_PLL_SRC_NONE, + TSCS42XX_PLL_SRC_XTAL, + TSCS42XX_PLL_SRC_MCLK1, + TSCS42XX_PLL_SRC_MCLK2, +}; + +#define R_HPVOLL 0x0 +#define R_HPVOLR 0x1 +#define R_SPKVOLL 0x2 +#define R_SPKVOLR 0x3 +#define R_DACVOLL 0x4 +#define R_DACVOLR 0x5 +#define R_ADCVOLL 0x6 +#define R_ADCVOLR 0x7 +#define R_INVOLL 0x8 +#define R_INVOLR 0x9 +#define R_INMODE 0x0B +#define R_INSELL 0x0C +#define R_INSELR 0x0D +#define R_AIC1 0x13 +#define R_AIC2 0x14 +#define R_CNVRTR0 0x16 +#define R_ADCSR 0x17 +#define R_CNVRTR1 0x18 +#define R_DACSR 0x19 +#define R_PWRM1 0x1A +#define R_PWRM2 0x1B +#define R_CONFIG0 0x1F +#define R_CONFIG1 0x20 +#define R_DMICCTL 0x24 +#define R_CLECTL 0x25 +#define R_MUGAIN 0x26 +#define R_COMPTH 0x27 +#define R_CMPRAT 0x28 +#define R_CATKTCL 0x29 +#define R_CATKTCH 0x2A +#define R_CRELTCL 0x2B +#define R_CRELTCH 0x2C +#define R_LIMTH 0x2D +#define R_LIMTGT 0x2E +#define R_LATKTCL 0x2F +#define R_LATKTCH 0x30 +#define R_LRELTCL 0x31 +#define R_LRELTCH 0x32 +#define R_EXPTH 0x33 +#define R_EXPRAT 0x34 +#define R_XATKTCL 0x35 +#define R_XATKTCH 0x36 +#define R_XRELTCL 0x37 +#define R_XRELTCH 0x38 +#define R_FXCTL 0x39 +#define R_DACCRWRL 0x3A +#define R_DACCRWRM 0x3B +#define R_DACCRWRH 0x3C +#define R_DACCRRDL 0x3D +#define R_DACCRRDM 0x3E +#define R_DACCRRDH 0x3F +#define R_DACCRADDR 0x40 +#define R_DCOFSEL 0x41 +#define R_PLLCTL9 0x4E +#define R_PLLCTLA 0x4F +#define R_PLLCTLB 0x50 +#define R_PLLCTLC 0x51 +#define R_PLLCTLD 0x52 +#define R_PLLCTLE 0x53 +#define R_PLLCTLF 0x54 +#define R_PLLCTL10 0x55 +#define R_PLLCTL11 0x56 +#define R_PLLCTL12 0x57 +#define R_PLLCTL1B 0x60 +#define R_PLLCTL1C 0x61 +#define R_TIMEBASE 0x77 +#define R_DEVIDL 0x7D +#define R_DEVIDH 0x7E +#define R_RESET 0x80 +#define R_DACCRSTAT 0x8A +#define R_PLLCTL0 0x8E +#define R_PLLREFSEL 0x8F +#define R_DACMBCEN 0xC7 +#define R_DACMBCCTL 0xC8 +#define R_DACMBCMUG1 0xC9 +#define R_DACMBCTHR1 0xCA +#define R_DACMBCRAT1 0xCB +#define R_DACMBCATK1L 0xCC +#define R_DACMBCATK1H 0xCD +#define R_DACMBCREL1L 0xCE +#define R_DACMBCREL1H 0xCF +#define R_DACMBCMUG2 0xD0 +#define R_DACMBCTHR2 0xD1 +#define R_DACMBCRAT2 0xD2 +#define R_DACMBCATK2L 0xD3 +#define R_DACMBCATK2H 0xD4 +#define R_DACMBCREL2L 0xD5 +#define R_DACMBCREL2H 0xD6 +#define R_DACMBCMUG3 0xD7 +#define R_DACMBCTHR3 0xD8 +#define R_DACMBCRAT3 0xD9 +#define R_DACMBCATK3L 0xDA +#define R_DACMBCATK3H 0xDB +#define R_DACMBCREL3L 0xDC +#define R_DACMBCREL3H 0xDD + +/* Helpers */ +#define RM(m, b) ((m)<<(b)) +#define RV(v, b) ((v)<<(b)) + +/**************************** + * R_HPVOLL (0x0) * + ****************************/ + +/* Field Offsets */ +#define FB_HPVOLL 0 + +/* Field Masks */ +#define FM_HPVOLL 0X7F + +/* Field Values */ +#define FV_HPVOLL_P6DB 0x7F +#define FV_HPVOLL_N88PT5DB 0x1 +#define FV_HPVOLL_MUTE 0x0 + +/* Register Masks */ +#define RM_HPVOLL RM(FM_HPVOLL, FB_HPVOLL) + +/* Register Values */ +#define RV_HPVOLL_P6DB RV(FV_HPVOLL_P6DB, FB_HPVOLL) +#define RV_HPVOLL_N88PT5DB RV(FV_HPVOLL_N88PT5DB, FB_HPVOLL) +#define RV_HPVOLL_MUTE RV(FV_HPVOLL_MUTE, FB_HPVOLL) + +/**************************** + * R_HPVOLR (0x1) * + ****************************/ + +/* Field Offsets */ +#define FB_HPVOLR 0 + +/* Field Masks */ +#define FM_HPVOLR 0X7F + +/* Field Values */ +#define FV_HPVOLR_P6DB 0x7F +#define FV_HPVOLR_N88PT5DB 0x1 +#define FV_HPVOLR_MUTE 0x0 + +/* Register Masks */ +#define RM_HPVOLR RM(FM_HPVOLR, FB_HPVOLR) + +/* Register Values */ +#define RV_HPVOLR_P6DB RV(FV_HPVOLR_P6DB, FB_HPVOLR) +#define RV_HPVOLR_N88PT5DB RV(FV_HPVOLR_N88PT5DB, FB_HPVOLR) +#define RV_HPVOLR_MUTE RV(FV_HPVOLR_MUTE, FB_HPVOLR) + +/***************************** + * R_SPKVOLL (0x2) * + *****************************/ + +/* Field Offsets */ +#define FB_SPKVOLL 0 + +/* Field Masks */ +#define FM_SPKVOLL 0X7F + +/* Field Values */ +#define FV_SPKVOLL_P12DB 0x7F +#define FV_SPKVOLL_N77PT25DB 0x8 +#define FV_SPKVOLL_MUTE 0x0 + +/* Register Masks */ +#define RM_SPKVOLL RM(FM_SPKVOLL, FB_SPKVOLL) + +/* Register Values */ +#define RV_SPKVOLL_P12DB RV(FV_SPKVOLL_P12DB, FB_SPKVOLL) +#define RV_SPKVOLL_N77PT25DB \ + RV(FV_SPKVOLL_N77PT25DB, FB_SPKVOLL) + +#define RV_SPKVOLL_MUTE RV(FV_SPKVOLL_MUTE, FB_SPKVOLL) + +/***************************** + * R_SPKVOLR (0x3) * + *****************************/ + +/* Field Offsets */ +#define FB_SPKVOLR 0 + +/* Field Masks */ +#define FM_SPKVOLR 0X7F + +/* Field Values */ +#define FV_SPKVOLR_P12DB 0x7F +#define FV_SPKVOLR_N77PT25DB 0x8 +#define FV_SPKVOLR_MUTE 0x0 + +/* Register Masks */ +#define RM_SPKVOLR RM(FM_SPKVOLR, FB_SPKVOLR) + +/* Register Values */ +#define RV_SPKVOLR_P12DB RV(FV_SPKVOLR_P12DB, FB_SPKVOLR) +#define RV_SPKVOLR_N77PT25DB \ + RV(FV_SPKVOLR_N77PT25DB, FB_SPKVOLR) + +#define RV_SPKVOLR_MUTE RV(FV_SPKVOLR_MUTE, FB_SPKVOLR) + +/***************************** + * R_DACVOLL (0x4) * + *****************************/ + +/* Field Offsets */ +#define FB_DACVOLL 0 + +/* Field Masks */ +#define FM_DACVOLL 0XFF + +/* Field Values */ +#define FV_DACVOLL_0DB 0xFF +#define FV_DACVOLL_N95PT625DB 0x1 +#define FV_DACVOLL_MUTE 0x0 + +/* Register Masks */ +#define RM_DACVOLL RM(FM_DACVOLL, FB_DACVOLL) + +/* Register Values */ +#define RV_DACVOLL_0DB RV(FV_DACVOLL_0DB, FB_DACVOLL) +#define RV_DACVOLL_N95PT625DB \ + RV(FV_DACVOLL_N95PT625DB, FB_DACVOLL) + +#define RV_DACVOLL_MUTE RV(FV_DACVOLL_MUTE, FB_DACVOLL) + +/***************************** + * R_DACVOLR (0x5) * + *****************************/ + +/* Field Offsets */ +#define FB_DACVOLR 0 + +/* Field Masks */ +#define FM_DACVOLR 0XFF + +/* Field Values */ +#define FV_DACVOLR_0DB 0xFF +#define FV_DACVOLR_N95PT625DB 0x1 +#define FV_DACVOLR_MUTE 0x0 + +/* Register Masks */ +#define RM_DACVOLR RM(FM_DACVOLR, FB_DACVOLR) + +/* Register Values */ +#define RV_DACVOLR_0DB RV(FV_DACVOLR_0DB, FB_DACVOLR) +#define RV_DACVOLR_N95PT625DB \ + RV(FV_DACVOLR_N95PT625DB, FB_DACVOLR) + +#define RV_DACVOLR_MUTE RV(FV_DACVOLR_MUTE, FB_DACVOLR) + +/***************************** + * R_ADCVOLL (0x6) * + *****************************/ + +/* Field Offsets */ +#define FB_ADCVOLL 0 + +/* Field Masks */ +#define FM_ADCVOLL 0XFF + +/* Field Values */ +#define FV_ADCVOLL_P24DB 0xFF +#define FV_ADCVOLL_N71PT25DB 0x1 +#define FV_ADCVOLL_MUTE 0x0 + +/* Register Masks */ +#define RM_ADCVOLL RM(FM_ADCVOLL, FB_ADCVOLL) + +/* Register Values */ +#define RV_ADCVOLL_P24DB RV(FV_ADCVOLL_P24DB, FB_ADCVOLL) +#define RV_ADCVOLL_N71PT25DB \ + RV(FV_ADCVOLL_N71PT25DB, FB_ADCVOLL) + +#define RV_ADCVOLL_MUTE RV(FV_ADCVOLL_MUTE, FB_ADCVOLL) + +/***************************** + * R_ADCVOLR (0x7) * + *****************************/ + +/* Field Offsets */ +#define FB_ADCVOLR 0 + +/* Field Masks */ +#define FM_ADCVOLR 0XFF + +/* Field Values */ +#define FV_ADCVOLR_P24DB 0xFF +#define FV_ADCVOLR_N71PT25DB 0x1 +#define FV_ADCVOLR_MUTE 0x0 + +/* Register Masks */ +#define RM_ADCVOLR RM(FM_ADCVOLR, FB_ADCVOLR) + +/* Register Values */ +#define RV_ADCVOLR_P24DB RV(FV_ADCVOLR_P24DB, FB_ADCVOLR) +#define RV_ADCVOLR_N71PT25DB \ + RV(FV_ADCVOLR_N71PT25DB, FB_ADCVOLR) + +#define RV_ADCVOLR_MUTE RV(FV_ADCVOLR_MUTE, FB_ADCVOLR) + +/**************************** + * R_INVOLL (0x8) * + ****************************/ + +/* Field Offsets */ +#define FB_INVOLL_INMUTEL 7 +#define FB_INVOLL_IZCL 6 +#define FB_INVOLL 0 + +/* Field Masks */ +#define FM_INVOLL_INMUTEL 0X1 +#define FM_INVOLL_IZCL 0X1 +#define FM_INVOLL 0X3F + +/* Field Values */ +#define FV_INVOLL_INMUTEL_ENABLE 0x1 +#define FV_INVOLL_INMUTEL_DISABLE 0x0 +#define FV_INVOLL_IZCL_ENABLE 0x1 +#define FV_INVOLL_IZCL_DISABLE 0x0 +#define FV_INVOLL_P30DB 0x3F +#define FV_INVOLL_N17PT25DB 0x0 + +/* Register Masks */ +#define RM_INVOLL_INMUTEL \ + RM(FM_INVOLL_INMUTEL, FB_INVOLL_INMUTEL) + +#define RM_INVOLL_IZCL RM(FM_INVOLL_IZCL, FB_INVOLL_IZCL) +#define RM_INVOLL RM(FM_INVOLL, FB_INVOLL) + +/* Register Values */ +#define RV_INVOLL_INMUTEL_ENABLE \ + RV(FV_INVOLL_INMUTEL_ENABLE, FB_INVOLL_INMUTEL) + +#define RV_INVOLL_INMUTEL_DISABLE \ + RV(FV_INVOLL_INMUTEL_DISABLE, FB_INVOLL_INMUTEL) + +#define RV_INVOLL_IZCL_ENABLE \ + RV(FV_INVOLL_IZCL_ENABLE, FB_INVOLL_IZCL) + +#define RV_INVOLL_IZCL_DISABLE \ + RV(FV_INVOLL_IZCL_DISABLE, FB_INVOLL_IZCL) + +#define RV_INVOLL_P30DB RV(FV_INVOLL_P30DB, FB_INVOLL) +#define RV_INVOLL_N17PT25DB RV(FV_INVOLL_N17PT25DB, FB_INVOLL) + +/**************************** + * R_INVOLR (0x9) * + ****************************/ + +/* Field Offsets */ +#define FB_INVOLR_INMUTER 7 +#define FB_INVOLR_IZCR 6 +#define FB_INVOLR 0 + +/* Field Masks */ +#define FM_INVOLR_INMUTER 0X1 +#define FM_INVOLR_IZCR 0X1 +#define FM_INVOLR 0X3F + +/* Field Values */ +#define FV_INVOLR_INMUTER_ENABLE 0x1 +#define FV_INVOLR_INMUTER_DISABLE 0x0 +#define FV_INVOLR_IZCR_ENABLE 0x1 +#define FV_INVOLR_IZCR_DISABLE 0x0 +#define FV_INVOLR_P30DB 0x3F +#define FV_INVOLR_N17PT25DB 0x0 + +/* Register Masks */ +#define RM_INVOLR_INMUTER \ + RM(FM_INVOLR_INMUTER, FB_INVOLR_INMUTER) + +#define RM_INVOLR_IZCR RM(FM_INVOLR_IZCR, FB_INVOLR_IZCR) +#define RM_INVOLR RM(FM_INVOLR, FB_INVOLR) + +/* Register Values */ +#define RV_INVOLR_INMUTER_ENABLE \ + RV(FV_INVOLR_INMUTER_ENABLE, FB_INVOLR_INMUTER) + +#define RV_INVOLR_INMUTER_DISABLE \ + RV(FV_INVOLR_INMUTER_DISABLE, FB_INVOLR_INMUTER) + +#define RV_INVOLR_IZCR_ENABLE \ + RV(FV_INVOLR_IZCR_ENABLE, FB_INVOLR_IZCR) + +#define RV_INVOLR_IZCR_DISABLE \ + RV(FV_INVOLR_IZCR_DISABLE, FB_INVOLR_IZCR) + +#define RV_INVOLR_P30DB RV(FV_INVOLR_P30DB, FB_INVOLR) +#define RV_INVOLR_N17PT25DB RV(FV_INVOLR_N17PT25DB, FB_INVOLR) + +/***************************** + * R_INMODE (0x0B) * + *****************************/ + +/* Field Offsets */ +#define FB_INMODE_DS 0 + +/* Field Masks */ +#define FM_INMODE_DS 0X1 + +/* Field Values */ +#define FV_INMODE_DS_LRIN1 0x0 +#define FV_INMODE_DS_LRIN2 0x1 + +/* Register Masks */ +#define RM_INMODE_DS RM(FM_INMODE_DS, FB_INMODE_DS) + +/* Register Values */ +#define RV_INMODE_DS_LRIN1 \ + RV(FV_INMODE_DS_LRIN1, FB_INMODE_DS) + +#define RV_INMODE_DS_LRIN2 \ + RV(FV_INMODE_DS_LRIN2, FB_INMODE_DS) + + +/***************************** + * R_INSELL (0x0C) * + *****************************/ + +/* Field Offsets */ +#define FB_INSELL 6 +#define FB_INSELL_MICBSTL 4 + +/* Field Masks */ +#define FM_INSELL 0X3 +#define FM_INSELL_MICBSTL 0X3 + +/* Field Values */ +#define FV_INSELL_IN1 0x0 +#define FV_INSELL_IN2 0x1 +#define FV_INSELL_IN3 0x2 +#define FV_INSELL_D2S 0x3 +#define FV_INSELL_MICBSTL_OFF 0x0 +#define FV_INSELL_MICBSTL_10DB 0x1 +#define FV_INSELL_MICBSTL_20DB 0x2 +#define FV_INSELL_MICBSTL_30DB 0x3 + +/* Register Masks */ +#define RM_INSELL RM(FM_INSELL, FB_INSELL) +#define RM_INSELL_MICBSTL \ + RM(FM_INSELL_MICBSTL, FB_INSELL_MICBSTL) + + +/* Register Values */ +#define RV_INSELL_IN1 RV(FV_INSELL_IN1, FB_INSELL) +#define RV_INSELL_IN2 RV(FV_INSELL_IN2, FB_INSELL) +#define RV_INSELL_IN3 RV(FV_INSELL_IN3, FB_INSELL) +#define RV_INSELL_D2S RV(FV_INSELL_D2S, FB_INSELL) +#define RV_INSELL_MICBSTL_OFF \ + RV(FV_INSELL_MICBSTL_OFF, FB_INSELL_MICBSTL) + +#define RV_INSELL_MICBSTL_10DB \ + RV(FV_INSELL_MICBSTL_10DB, FB_INSELL_MICBSTL) + +#define RV_INSELL_MICBSTL_20DB \ + RV(FV_INSELL_MICBSTL_20DB, FB_INSELL_MICBSTL) + +#define RV_INSELL_MICBSTL_30DB \ + RV(FV_INSELL_MICBSTL_30DB, FB_INSELL_MICBSTL) + + +/***************************** + * R_INSELR (0x0D) * + *****************************/ + +/* Field Offsets */ +#define FB_INSELR 6 +#define FB_INSELR_MICBSTR 4 + +/* Field Masks */ +#define FM_INSELR 0X3 +#define FM_INSELR_MICBSTR 0X3 + +/* Field Values */ +#define FV_INSELR_IN1 0x0 +#define FV_INSELR_IN2 0x1 +#define FV_INSELR_IN3 0x2 +#define FV_INSELR_D2S 0x3 +#define FV_INSELR_MICBSTR_OFF 0x0 +#define FV_INSELR_MICBSTR_10DB 0x1 +#define FV_INSELR_MICBSTR_20DB 0x2 +#define FV_INSELR_MICBSTR_30DB 0x3 + +/* Register Masks */ +#define RM_INSELR RM(FM_INSELR, FB_INSELR) +#define RM_INSELR_MICBSTR \ + RM(FM_INSELR_MICBSTR, FB_INSELR_MICBSTR) + + +/* Register Values */ +#define RV_INSELR_IN1 RV(FV_INSELR_IN1, FB_INSELR) +#define RV_INSELR_IN2 RV(FV_INSELR_IN2, FB_INSELR) +#define RV_INSELR_IN3 RV(FV_INSELR_IN3, FB_INSELR) +#define RV_INSELR_D2S RV(FV_INSELR_D2S, FB_INSELR) +#define RV_INSELR_MICBSTR_OFF \ + RV(FV_INSELR_MICBSTR_OFF, FB_INSELR_MICBSTR) + +#define RV_INSELR_MICBSTR_10DB \ + RV(FV_INSELR_MICBSTR_10DB, FB_INSELR_MICBSTR) + +#define RV_INSELR_MICBSTR_20DB \ + RV(FV_INSELR_MICBSTR_20DB, FB_INSELR_MICBSTR) + +#define RV_INSELR_MICBSTR_30DB \ + RV(FV_INSELR_MICBSTR_30DB, FB_INSELR_MICBSTR) + + +/*************************** + * R_AIC1 (0x13) * + ***************************/ + +/* Field Offsets */ +#define FB_AIC1_BCLKINV 6 +#define FB_AIC1_MS 5 +#define FB_AIC1_LRP 4 +#define FB_AIC1_WL 2 +#define FB_AIC1_FORMAT 0 + +/* Field Masks */ +#define FM_AIC1_BCLKINV 0X1 +#define FM_AIC1_MS 0X1 +#define FM_AIC1_LRP 0X1 +#define FM_AIC1_WL 0X3 +#define FM_AIC1_FORMAT 0X3 + +/* Field Values */ +#define FV_AIC1_BCLKINV_ENABLE 0x1 +#define FV_AIC1_BCLKINV_DISABLE 0x0 +#define FV_AIC1_MS_MASTER 0x1 +#define FV_AIC1_MS_SLAVE 0x0 +#define FV_AIC1_LRP_INVERT 0x1 +#define FV_AIC1_LRP_NORMAL 0x0 +#define FV_AIC1_WL_16 0x0 +#define FV_AIC1_WL_20 0x1 +#define FV_AIC1_WL_24 0x2 +#define FV_AIC1_WL_32 0x3 +#define FV_AIC1_FORMAT_RIGHT 0x0 +#define FV_AIC1_FORMAT_LEFT 0x1 +#define FV_AIC1_FORMAT_I2S 0x2 + +/* Register Masks */ +#define RM_AIC1_BCLKINV \ + RM(FM_AIC1_BCLKINV, FB_AIC1_BCLKINV) + +#define RM_AIC1_MS RM(FM_AIC1_MS, FB_AIC1_MS) +#define RM_AIC1_LRP RM(FM_AIC1_LRP, FB_AIC1_LRP) +#define RM_AIC1_WL RM(FM_AIC1_WL, FB_AIC1_WL) +#define RM_AIC1_FORMAT RM(FM_AIC1_FORMAT, FB_AIC1_FORMAT) + +/* Register Values */ +#define RV_AIC1_BCLKINV_ENABLE \ + RV(FV_AIC1_BCLKINV_ENABLE, FB_AIC1_BCLKINV) + +#define RV_AIC1_BCLKINV_DISABLE \ + RV(FV_AIC1_BCLKINV_DISABLE, FB_AIC1_BCLKINV) + +#define RV_AIC1_MS_MASTER RV(FV_AIC1_MS_MASTER, FB_AIC1_MS) +#define RV_AIC1_MS_SLAVE RV(FV_AIC1_MS_SLAVE, FB_AIC1_MS) +#define RV_AIC1_LRP_INVERT \ + RV(FV_AIC1_LRP_INVERT, FB_AIC1_LRP) + +#define RV_AIC1_LRP_NORMAL \ + RV(FV_AIC1_LRP_NORMAL, FB_AIC1_LRP) + +#define RV_AIC1_WL_16 RV(FV_AIC1_WL_16, FB_AIC1_WL) +#define RV_AIC1_WL_20 RV(FV_AIC1_WL_20, FB_AIC1_WL) +#define RV_AIC1_WL_24 RV(FV_AIC1_WL_24, FB_AIC1_WL) +#define RV_AIC1_WL_32 RV(FV_AIC1_WL_32, FB_AIC1_WL) +#define RV_AIC1_FORMAT_RIGHT \ + RV(FV_AIC1_FORMAT_RIGHT, FB_AIC1_FORMAT) + +#define RV_AIC1_FORMAT_LEFT \ + RV(FV_AIC1_FORMAT_LEFT, FB_AIC1_FORMAT) + +#define RV_AIC1_FORMAT_I2S \ + RV(FV_AIC1_FORMAT_I2S, FB_AIC1_FORMAT) + + +/*************************** + * R_AIC2 (0x14) * + ***************************/ + +/* Field Offsets */ +#define FB_AIC2_DACDSEL 6 +#define FB_AIC2_ADCDSEL 4 +#define FB_AIC2_TRI 3 +#define FB_AIC2_BLRCM 0 + +/* Field Masks */ +#define FM_AIC2_DACDSEL 0X3 +#define FM_AIC2_ADCDSEL 0X3 +#define FM_AIC2_TRI 0X1 +#define FM_AIC2_BLRCM 0X7 + +/* Field Values */ +#define FV_AIC2_BLRCM_DAC_BCLK_LRCLK_SHARED 0x3 + +/* Register Masks */ +#define RM_AIC2_DACDSEL \ + RM(FM_AIC2_DACDSEL, FB_AIC2_DACDSEL) + +#define RM_AIC2_ADCDSEL \ + RM(FM_AIC2_ADCDSEL, FB_AIC2_ADCDSEL) + +#define RM_AIC2_TRI RM(FM_AIC2_TRI, FB_AIC2_TRI) +#define RM_AIC2_BLRCM RM(FM_AIC2_BLRCM, FB_AIC2_BLRCM) + +/* Register Values */ +#define RV_AIC2_BLRCM_DAC_BCLK_LRCLK_SHARED \ + RV(FV_AIC2_BLRCM_DAC_BCLK_LRCLK_SHARED, FB_AIC2_BLRCM) + + +/****************************** + * R_CNVRTR0 (0x16) * + ******************************/ + +/* Field Offsets */ +#define FB_CNVRTR0_ADCPOLR 7 +#define FB_CNVRTR0_ADCPOLL 6 +#define FB_CNVRTR0_AMONOMIX 4 +#define FB_CNVRTR0_ADCMU 3 +#define FB_CNVRTR0_HPOR 2 +#define FB_CNVRTR0_ADCHPDR 1 +#define FB_CNVRTR0_ADCHPDL 0 + +/* Field Masks */ +#define FM_CNVRTR0_ADCPOLR 0X1 +#define FM_CNVRTR0_ADCPOLL 0X1 +#define FM_CNVRTR0_AMONOMIX 0X3 +#define FM_CNVRTR0_ADCMU 0X1 +#define FM_CNVRTR0_HPOR 0X1 +#define FM_CNVRTR0_ADCHPDR 0X1 +#define FM_CNVRTR0_ADCHPDL 0X1 + +/* Field Values */ +#define FV_CNVRTR0_ADCPOLR_INVERT 0x1 +#define FV_CNVRTR0_ADCPOLR_NORMAL 0x0 +#define FV_CNVRTR0_ADCPOLL_INVERT 0x1 +#define FV_CNVRTR0_ADCPOLL_NORMAL 0x0 +#define FV_CNVRTR0_ADCMU_ENABLE 0x1 +#define FV_CNVRTR0_ADCMU_DISABLE 0x0 +#define FV_CNVRTR0_ADCHPDR_ENABLE 0x1 +#define FV_CNVRTR0_ADCHPDR_DISABLE 0x0 +#define FV_CNVRTR0_ADCHPDL_ENABLE 0x1 +#define FV_CNVRTR0_ADCHPDL_DISABLE 0x0 + +/* Register Masks */ +#define RM_CNVRTR0_ADCPOLR \ + RM(FM_CNVRTR0_ADCPOLR, FB_CNVRTR0_ADCPOLR) + +#define RM_CNVRTR0_ADCPOLL \ + RM(FM_CNVRTR0_ADCPOLL, FB_CNVRTR0_ADCPOLL) + +#define RM_CNVRTR0_AMONOMIX \ + RM(FM_CNVRTR0_AMONOMIX, FB_CNVRTR0_AMONOMIX) + +#define RM_CNVRTR0_ADCMU \ + RM(FM_CNVRTR0_ADCMU, FB_CNVRTR0_ADCMU) + +#define RM_CNVRTR0_HPOR \ + RM(FM_CNVRTR0_HPOR, FB_CNVRTR0_HPOR) + +#define RM_CNVRTR0_ADCHPDR \ + RM(FM_CNVRTR0_ADCHPDR, FB_CNVRTR0_ADCHPDR) + +#define RM_CNVRTR0_ADCHPDL \ + RM(FM_CNVRTR0_ADCHPDL, FB_CNVRTR0_ADCHPDL) + + +/* Register Values */ +#define RV_CNVRTR0_ADCPOLR_INVERT \ + RV(FV_CNVRTR0_ADCPOLR_INVERT, FB_CNVRTR0_ADCPOLR) + +#define RV_CNVRTR0_ADCPOLR_NORMAL \ + RV(FV_CNVRTR0_ADCPOLR_NORMAL, FB_CNVRTR0_ADCPOLR) + +#define RV_CNVRTR0_ADCPOLL_INVERT \ + RV(FV_CNVRTR0_ADCPOLL_INVERT, FB_CNVRTR0_ADCPOLL) + +#define RV_CNVRTR0_ADCPOLL_NORMAL \ + RV(FV_CNVRTR0_ADCPOLL_NORMAL, FB_CNVRTR0_ADCPOLL) + +#define RV_CNVRTR0_ADCMU_ENABLE \ + RV(FV_CNVRTR0_ADCMU_ENABLE, FB_CNVRTR0_ADCMU) + +#define RV_CNVRTR0_ADCMU_DISABLE \ + RV(FV_CNVRTR0_ADCMU_DISABLE, FB_CNVRTR0_ADCMU) + +#define RV_CNVRTR0_ADCHPDR_ENABLE \ + RV(FV_CNVRTR0_ADCHPDR_ENABLE, FB_CNVRTR0_ADCHPDR) + +#define RV_CNVRTR0_ADCHPDR_DISABLE \ + RV(FV_CNVRTR0_ADCHPDR_DISABLE, FB_CNVRTR0_ADCHPDR) + +#define RV_CNVRTR0_ADCHPDL_ENABLE \ + RV(FV_CNVRTR0_ADCHPDL_ENABLE, FB_CNVRTR0_ADCHPDL) + +#define RV_CNVRTR0_ADCHPDL_DISABLE \ + RV(FV_CNVRTR0_ADCHPDL_DISABLE, FB_CNVRTR0_ADCHPDL) + + +/**************************** + * R_ADCSR (0x17) * + ****************************/ + +/* Field Offsets */ +#define FB_ADCSR_ABCM 6 +#define FB_ADCSR_ABR 3 +#define FB_ADCSR_ABM 0 + +/* Field Masks */ +#define FM_ADCSR_ABCM 0X3 +#define FM_ADCSR_ABR 0X3 +#define FM_ADCSR_ABM 0X7 + +/* Field Values */ +#define FV_ADCSR_ABCM_AUTO 0x0 +#define FV_ADCSR_ABCM_32 0x1 +#define FV_ADCSR_ABCM_40 0x2 +#define FV_ADCSR_ABCM_64 0x3 +#define FV_ADCSR_ABR_32 0x0 +#define FV_ADCSR_ABR_44_1 0x1 +#define FV_ADCSR_ABR_48 0x2 +#define FV_ADCSR_ABM_PT25 0x0 +#define FV_ADCSR_ABM_PT5 0x1 +#define FV_ADCSR_ABM_1 0x2 +#define FV_ADCSR_ABM_2 0x3 + +/* Register Masks */ +#define RM_ADCSR_ABCM RM(FM_ADCSR_ABCM, FB_ADCSR_ABCM) +#define RM_ADCSR_ABR RM(FM_ADCSR_ABR, FB_ADCSR_ABR) +#define RM_ADCSR_ABM RM(FM_ADCSR_ABM, FB_ADCSR_ABM) + +/* Register Values */ +#define RV_ADCSR_ABCM_AUTO \ + RV(FV_ADCSR_ABCM_AUTO, FB_ADCSR_ABCM) + +#define RV_ADCSR_ABCM_32 \ + RV(FV_ADCSR_ABCM_32, FB_ADCSR_ABCM) + +#define RV_ADCSR_ABCM_40 \ + RV(FV_ADCSR_ABCM_40, FB_ADCSR_ABCM) + +#define RV_ADCSR_ABCM_64 \ + RV(FV_ADCSR_ABCM_64, FB_ADCSR_ABCM) + +#define RV_ADCSR_ABR_32 RV(FV_ADCSR_ABR_32, FB_ADCSR_ABR) +#define RV_ADCSR_ABR_44_1 \ + RV(FV_ADCSR_ABR_44_1, FB_ADCSR_ABR) + +#define RV_ADCSR_ABR_48 RV(FV_ADCSR_ABR_48, FB_ADCSR_ABR) +#define RV_ADCSR_ABR_ RV(FV_ADCSR_ABR_, FB_ADCSR_ABR) +#define RV_ADCSR_ABM_PT25 \ + RV(FV_ADCSR_ABM_PT25, FB_ADCSR_ABM) + +#define RV_ADCSR_ABM_PT5 RV(FV_ADCSR_ABM_PT5, FB_ADCSR_ABM) +#define RV_ADCSR_ABM_1 RV(FV_ADCSR_ABM_1, FB_ADCSR_ABM) +#define RV_ADCSR_ABM_2 RV(FV_ADCSR_ABM_2, FB_ADCSR_ABM) + +/****************************** + * R_CNVRTR1 (0x18) * + ******************************/ + +/* Field Offsets */ +#define FB_CNVRTR1_DACPOLR 7 +#define FB_CNVRTR1_DACPOLL 6 +#define FB_CNVRTR1_DMONOMIX 4 +#define FB_CNVRTR1_DACMU 3 +#define FB_CNVRTR1_DEEMPH 2 +#define FB_CNVRTR1_DACDITH 0 + +/* Field Masks */ +#define FM_CNVRTR1_DACPOLR 0X1 +#define FM_CNVRTR1_DACPOLL 0X1 +#define FM_CNVRTR1_DMONOMIX 0X3 +#define FM_CNVRTR1_DACMU 0X1 +#define FM_CNVRTR1_DEEMPH 0X1 +#define FM_CNVRTR1_DACDITH 0X3 + +/* Field Values */ +#define FV_CNVRTR1_DACPOLR_INVERT 0x1 +#define FV_CNVRTR1_DACPOLR_NORMAL 0x0 +#define FV_CNVRTR1_DACPOLL_INVERT 0x1 +#define FV_CNVRTR1_DACPOLL_NORMAL 0x0 +#define FV_CNVRTR1_DMONOMIX_ENABLE 0x1 +#define FV_CNVRTR1_DMONOMIX_DISABLE 0x0 +#define FV_CNVRTR1_DACMU_ENABLE 0x1 +#define FV_CNVRTR1_DACMU_DISABLE 0x0 + +/* Register Masks */ +#define RM_CNVRTR1_DACPOLR \ + RM(FM_CNVRTR1_DACPOLR, FB_CNVRTR1_DACPOLR) + +#define RM_CNVRTR1_DACPOLL \ + RM(FM_CNVRTR1_DACPOLL, FB_CNVRTR1_DACPOLL) + +#define RM_CNVRTR1_DMONOMIX \ + RM(FM_CNVRTR1_DMONOMIX, FB_CNVRTR1_DMONOMIX) + +#define RM_CNVRTR1_DACMU \ + RM(FM_CNVRTR1_DACMU, FB_CNVRTR1_DACMU) + +#define RM_CNVRTR1_DEEMPH \ + RM(FM_CNVRTR1_DEEMPH, FB_CNVRTR1_DEEMPH) + +#define RM_CNVRTR1_DACDITH \ + RM(FM_CNVRTR1_DACDITH, FB_CNVRTR1_DACDITH) + + +/* Register Values */ +#define RV_CNVRTR1_DACPOLR_INVERT \ + RV(FV_CNVRTR1_DACPOLR_INVERT, FB_CNVRTR1_DACPOLR) + +#define RV_CNVRTR1_DACPOLR_NORMAL \ + RV(FV_CNVRTR1_DACPOLR_NORMAL, FB_CNVRTR1_DACPOLR) + +#define RV_CNVRTR1_DACPOLL_INVERT \ + RV(FV_CNVRTR1_DACPOLL_INVERT, FB_CNVRTR1_DACPOLL) + +#define RV_CNVRTR1_DACPOLL_NORMAL \ + RV(FV_CNVRTR1_DACPOLL_NORMAL, FB_CNVRTR1_DACPOLL) + +#define RV_CNVRTR1_DMONOMIX_ENABLE \ + RV(FV_CNVRTR1_DMONOMIX_ENABLE, FB_CNVRTR1_DMONOMIX) + +#define RV_CNVRTR1_DMONOMIX_DISABLE \ + RV(FV_CNVRTR1_DMONOMIX_DISABLE, FB_CNVRTR1_DMONOMIX) + +#define RV_CNVRTR1_DACMU_ENABLE \ + RV(FV_CNVRTR1_DACMU_ENABLE, FB_CNVRTR1_DACMU) + +#define RV_CNVRTR1_DACMU_DISABLE \ + RV(FV_CNVRTR1_DACMU_DISABLE, FB_CNVRTR1_DACMU) + + +/**************************** + * R_DACSR (0x19) * + ****************************/ + +/* Field Offsets */ +#define FB_DACSR_DBCM 6 +#define FB_DACSR_DBR 3 +#define FB_DACSR_DBM 0 + +/* Field Masks */ +#define FM_DACSR_DBCM 0X3 +#define FM_DACSR_DBR 0X3 +#define FM_DACSR_DBM 0X7 + +/* Field Values */ +#define FV_DACSR_DBCM_AUTO 0x0 +#define FV_DACSR_DBCM_32 0x1 +#define FV_DACSR_DBCM_40 0x2 +#define FV_DACSR_DBCM_64 0x3 +#define FV_DACSR_DBR_32 0x0 +#define FV_DACSR_DBR_44_1 0x1 +#define FV_DACSR_DBR_48 0x2 +#define FV_DACSR_DBM_PT25 0x0 +#define FV_DACSR_DBM_PT5 0x1 +#define FV_DACSR_DBM_1 0x2 +#define FV_DACSR_DBM_2 0x3 + +/* Register Masks */ +#define RM_DACSR_DBCM RM(FM_DACSR_DBCM, FB_DACSR_DBCM) +#define RM_DACSR_DBR RM(FM_DACSR_DBR, FB_DACSR_DBR) +#define RM_DACSR_DBM RM(FM_DACSR_DBM, FB_DACSR_DBM) + +/* Register Values */ +#define RV_DACSR_DBCM_AUTO \ + RV(FV_DACSR_DBCM_AUTO, FB_DACSR_DBCM) + +#define RV_DACSR_DBCM_32 \ + RV(FV_DACSR_DBCM_32, FB_DACSR_DBCM) + +#define RV_DACSR_DBCM_40 \ + RV(FV_DACSR_DBCM_40, FB_DACSR_DBCM) + +#define RV_DACSR_DBCM_64 \ + RV(FV_DACSR_DBCM_64, FB_DACSR_DBCM) + +#define RV_DACSR_DBR_32 RV(FV_DACSR_DBR_32, FB_DACSR_DBR) +#define RV_DACSR_DBR_44_1 \ + RV(FV_DACSR_DBR_44_1, FB_DACSR_DBR) + +#define RV_DACSR_DBR_48 RV(FV_DACSR_DBR_48, FB_DACSR_DBR) +#define RV_DACSR_DBM_PT25 \ + RV(FV_DACSR_DBM_PT25, FB_DACSR_DBM) + +#define RV_DACSR_DBM_PT5 RV(FV_DACSR_DBM_PT5, FB_DACSR_DBM) +#define RV_DACSR_DBM_1 RV(FV_DACSR_DBM_1, FB_DACSR_DBM) +#define RV_DACSR_DBM_2 RV(FV_DACSR_DBM_2, FB_DACSR_DBM) + +/**************************** + * R_PWRM1 (0x1A) * + ****************************/ + +/* Field Offsets */ +#define FB_PWRM1_BSTL 7 +#define FB_PWRM1_BSTR 6 +#define FB_PWRM1_PGAL 5 +#define FB_PWRM1_PGAR 4 +#define FB_PWRM1_ADCL 3 +#define FB_PWRM1_ADCR 2 +#define FB_PWRM1_MICB 1 +#define FB_PWRM1_DIGENB 0 + +/* Field Masks */ +#define FM_PWRM1_BSTL 0X1 +#define FM_PWRM1_BSTR 0X1 +#define FM_PWRM1_PGAL 0X1 +#define FM_PWRM1_PGAR 0X1 +#define FM_PWRM1_ADCL 0X1 +#define FM_PWRM1_ADCR 0X1 +#define FM_PWRM1_MICB 0X1 +#define FM_PWRM1_DIGENB 0X1 + +/* Field Values */ +#define FV_PWRM1_BSTL_ENABLE 0x1 +#define FV_PWRM1_BSTL_DISABLE 0x0 +#define FV_PWRM1_BSTR_ENABLE 0x1 +#define FV_PWRM1_BSTR_DISABLE 0x0 +#define FV_PWRM1_PGAL_ENABLE 0x1 +#define FV_PWRM1_PGAL_DISABLE 0x0 +#define FV_PWRM1_PGAR_ENABLE 0x1 +#define FV_PWRM1_PGAR_DISABLE 0x0 +#define FV_PWRM1_ADCL_ENABLE 0x1 +#define FV_PWRM1_ADCL_DISABLE 0x0 +#define FV_PWRM1_ADCR_ENABLE 0x1 +#define FV_PWRM1_ADCR_DISABLE 0x0 +#define FV_PWRM1_MICB_ENABLE 0x1 +#define FV_PWRM1_MICB_DISABLE 0x0 +#define FV_PWRM1_DIGENB_DISABLE 0x1 +#define FV_PWRM1_DIGENB_ENABLE 0x0 + +/* Register Masks */ +#define RM_PWRM1_BSTL RM(FM_PWRM1_BSTL, FB_PWRM1_BSTL) +#define RM_PWRM1_BSTR RM(FM_PWRM1_BSTR, FB_PWRM1_BSTR) +#define RM_PWRM1_PGAL RM(FM_PWRM1_PGAL, FB_PWRM1_PGAL) +#define RM_PWRM1_PGAR RM(FM_PWRM1_PGAR, FB_PWRM1_PGAR) +#define RM_PWRM1_ADCL RM(FM_PWRM1_ADCL, FB_PWRM1_ADCL) +#define RM_PWRM1_ADCR RM(FM_PWRM1_ADCR, FB_PWRM1_ADCR) +#define RM_PWRM1_MICB RM(FM_PWRM1_MICB, FB_PWRM1_MICB) +#define RM_PWRM1_DIGENB \ + RM(FM_PWRM1_DIGENB, FB_PWRM1_DIGENB) + + +/* Register Values */ +#define RV_PWRM1_BSTL_ENABLE \ + RV(FV_PWRM1_BSTL_ENABLE, FB_PWRM1_BSTL) + +#define RV_PWRM1_BSTL_DISABLE \ + RV(FV_PWRM1_BSTL_DISABLE, FB_PWRM1_BSTL) + +#define RV_PWRM1_BSTR_ENABLE \ + RV(FV_PWRM1_BSTR_ENABLE, FB_PWRM1_BSTR) + +#define RV_PWRM1_BSTR_DISABLE \ + RV(FV_PWRM1_BSTR_DISABLE, FB_PWRM1_BSTR) + +#define RV_PWRM1_PGAL_ENABLE \ + RV(FV_PWRM1_PGAL_ENABLE, FB_PWRM1_PGAL) + +#define RV_PWRM1_PGAL_DISABLE \ + RV(FV_PWRM1_PGAL_DISABLE, FB_PWRM1_PGAL) + +#define RV_PWRM1_PGAR_ENABLE \ + RV(FV_PWRM1_PGAR_ENABLE, FB_PWRM1_PGAR) + +#define RV_PWRM1_PGAR_DISABLE \ + RV(FV_PWRM1_PGAR_DISABLE, FB_PWRM1_PGAR) + +#define RV_PWRM1_ADCL_ENABLE \ + RV(FV_PWRM1_ADCL_ENABLE, FB_PWRM1_ADCL) + +#define RV_PWRM1_ADCL_DISABLE \ + RV(FV_PWRM1_ADCL_DISABLE, FB_PWRM1_ADCL) + +#define RV_PWRM1_ADCR_ENABLE \ + RV(FV_PWRM1_ADCR_ENABLE, FB_PWRM1_ADCR) + +#define RV_PWRM1_ADCR_DISABLE \ + RV(FV_PWRM1_ADCR_DISABLE, FB_PWRM1_ADCR) + +#define RV_PWRM1_MICB_ENABLE \ + RV(FV_PWRM1_MICB_ENABLE, FB_PWRM1_MICB) + +#define RV_PWRM1_MICB_DISABLE \ + RV(FV_PWRM1_MICB_DISABLE, FB_PWRM1_MICB) + +#define RV_PWRM1_DIGENB_DISABLE \ + RV(FV_PWRM1_DIGENB_DISABLE, FB_PWRM1_DIGENB) + +#define RV_PWRM1_DIGENB_ENABLE \ + RV(FV_PWRM1_DIGENB_ENABLE, FB_PWRM1_DIGENB) + + +/**************************** + * R_PWRM2 (0x1B) * + ****************************/ + +/* Field Offsets */ +#define FB_PWRM2_D2S 7 +#define FB_PWRM2_HPL 6 +#define FB_PWRM2_HPR 5 +#define FB_PWRM2_SPKL 4 +#define FB_PWRM2_SPKR 3 +#define FB_PWRM2_INSELL 2 +#define FB_PWRM2_INSELR 1 +#define FB_PWRM2_VREF 0 + +/* Field Masks */ +#define FM_PWRM2_D2S 0X1 +#define FM_PWRM2_HPL 0X1 +#define FM_PWRM2_HPR 0X1 +#define FM_PWRM2_SPKL 0X1 +#define FM_PWRM2_SPKR 0X1 +#define FM_PWRM2_INSELL 0X1 +#define FM_PWRM2_INSELR 0X1 +#define FM_PWRM2_VREF 0X1 + +/* Field Values */ +#define FV_PWRM2_D2S_ENABLE 0x1 +#define FV_PWRM2_D2S_DISABLE 0x0 +#define FV_PWRM2_HPL_ENABLE 0x1 +#define FV_PWRM2_HPL_DISABLE 0x0 +#define FV_PWRM2_HPR_ENABLE 0x1 +#define FV_PWRM2_HPR_DISABLE 0x0 +#define FV_PWRM2_SPKL_ENABLE 0x1 +#define FV_PWRM2_SPKL_DISABLE 0x0 +#define FV_PWRM2_SPKR_ENABLE 0x1 +#define FV_PWRM2_SPKR_DISABLE 0x0 +#define FV_PWRM2_INSELL_ENABLE 0x1 +#define FV_PWRM2_INSELL_DISABLE 0x0 +#define FV_PWRM2_INSELR_ENABLE 0x1 +#define FV_PWRM2_INSELR_DISABLE 0x0 +#define FV_PWRM2_VREF_ENABLE 0x1 +#define FV_PWRM2_VREF_DISABLE 0x0 + +/* Register Masks */ +#define RM_PWRM2_D2S RM(FM_PWRM2_D2S, FB_PWRM2_D2S) +#define RM_PWRM2_HPL RM(FM_PWRM2_HPL, FB_PWRM2_HPL) +#define RM_PWRM2_HPR RM(FM_PWRM2_HPR, FB_PWRM2_HPR) +#define RM_PWRM2_SPKL RM(FM_PWRM2_SPKL, FB_PWRM2_SPKL) +#define RM_PWRM2_SPKR RM(FM_PWRM2_SPKR, FB_PWRM2_SPKR) +#define RM_PWRM2_INSELL \ + RM(FM_PWRM2_INSELL, FB_PWRM2_INSELL) + +#define RM_PWRM2_INSELR \ + RM(FM_PWRM2_INSELR, FB_PWRM2_INSELR) + +#define RM_PWRM2_VREF RM(FM_PWRM2_VREF, FB_PWRM2_VREF) + +/* Register Values */ +#define RV_PWRM2_D2S_ENABLE \ + RV(FV_PWRM2_D2S_ENABLE, FB_PWRM2_D2S) + +#define RV_PWRM2_D2S_DISABLE \ + RV(FV_PWRM2_D2S_DISABLE, FB_PWRM2_D2S) + +#define RV_PWRM2_HPL_ENABLE \ + RV(FV_PWRM2_HPL_ENABLE, FB_PWRM2_HPL) + +#define RV_PWRM2_HPL_DISABLE \ + RV(FV_PWRM2_HPL_DISABLE, FB_PWRM2_HPL) + +#define RV_PWRM2_HPR_ENABLE \ + RV(FV_PWRM2_HPR_ENABLE, FB_PWRM2_HPR) + +#define RV_PWRM2_HPR_DISABLE \ + RV(FV_PWRM2_HPR_DISABLE, FB_PWRM2_HPR) + +#define RV_PWRM2_SPKL_ENABLE \ + RV(FV_PWRM2_SPKL_ENABLE, FB_PWRM2_SPKL) + +#define RV_PWRM2_SPKL_DISABLE \ + RV(FV_PWRM2_SPKL_DISABLE, FB_PWRM2_SPKL) + +#define RV_PWRM2_SPKR_ENABLE \ + RV(FV_PWRM2_SPKR_ENABLE, FB_PWRM2_SPKR) + +#define RV_PWRM2_SPKR_DISABLE \ + RV(FV_PWRM2_SPKR_DISABLE, FB_PWRM2_SPKR) + +#define RV_PWRM2_INSELL_ENABLE \ + RV(FV_PWRM2_INSELL_ENABLE, FB_PWRM2_INSELL) + +#define RV_PWRM2_INSELL_DISABLE \ + RV(FV_PWRM2_INSELL_DISABLE, FB_PWRM2_INSELL) + +#define RV_PWRM2_INSELR_ENABLE \ + RV(FV_PWRM2_INSELR_ENABLE, FB_PWRM2_INSELR) + +#define RV_PWRM2_INSELR_DISABLE \ + RV(FV_PWRM2_INSELR_DISABLE, FB_PWRM2_INSELR) + +#define RV_PWRM2_VREF_ENABLE \ + RV(FV_PWRM2_VREF_ENABLE, FB_PWRM2_VREF) + +#define RV_PWRM2_VREF_DISABLE \ + RV(FV_PWRM2_VREF_DISABLE, FB_PWRM2_VREF) + + +/****************************** + * R_CONFIG0 (0x1F) * + ******************************/ + +/* Field Offsets */ +#define FB_CONFIG0_ASDM 6 +#define FB_CONFIG0_DSDM 4 +#define FB_CONFIG0_DC_BYPASS 1 +#define FB_CONFIG0_SD_FORCE_ON 0 + +/* Field Masks */ +#define FM_CONFIG0_ASDM 0X3 +#define FM_CONFIG0_DSDM 0X3 +#define FM_CONFIG0_DC_BYPASS 0X1 +#define FM_CONFIG0_SD_FORCE_ON 0X1 + +/* Field Values */ +#define FV_CONFIG0_ASDM_HALF 0x1 +#define FV_CONFIG0_ASDM_FULL 0x2 +#define FV_CONFIG0_ASDM_AUTO 0x3 +#define FV_CONFIG0_DSDM_HALF 0x1 +#define FV_CONFIG0_DSDM_FULL 0x2 +#define FV_CONFIG0_DSDM_AUTO 0x3 +#define FV_CONFIG0_DC_BYPASS_ENABLE 0x1 +#define FV_CONFIG0_DC_BYPASS_DISABLE 0x0 +#define FV_CONFIG0_SD_FORCE_ON_ENABLE 0x1 +#define FV_CONFIG0_SD_FORCE_ON_DISABLE 0x0 + +/* Register Masks */ +#define RM_CONFIG0_ASDM \ + RM(FM_CONFIG0_ASDM, FB_CONFIG0_ASDM) + +#define RM_CONFIG0_DSDM \ + RM(FM_CONFIG0_DSDM, FB_CONFIG0_DSDM) + +#define RM_CONFIG0_DC_BYPASS \ + RM(FM_CONFIG0_DC_BYPASS, FB_CONFIG0_DC_BYPASS) + +#define RM_CONFIG0_SD_FORCE_ON \ + RM(FM_CONFIG0_SD_FORCE_ON, FB_CONFIG0_SD_FORCE_ON) + + +/* Register Values */ +#define RV_CONFIG0_ASDM_HALF \ + RV(FV_CONFIG0_ASDM_HALF, FB_CONFIG0_ASDM) + +#define RV_CONFIG0_ASDM_FULL \ + RV(FV_CONFIG0_ASDM_FULL, FB_CONFIG0_ASDM) + +#define RV_CONFIG0_ASDM_AUTO \ + RV(FV_CONFIG0_ASDM_AUTO, FB_CONFIG0_ASDM) + +#define RV_CONFIG0_DSDM_HALF \ + RV(FV_CONFIG0_DSDM_HALF, FB_CONFIG0_DSDM) + +#define RV_CONFIG0_DSDM_FULL \ + RV(FV_CONFIG0_DSDM_FULL, FB_CONFIG0_DSDM) + +#define RV_CONFIG0_DSDM_AUTO \ + RV(FV_CONFIG0_DSDM_AUTO, FB_CONFIG0_DSDM) + +#define RV_CONFIG0_DC_BYPASS_ENABLE \ + RV(FV_CONFIG0_DC_BYPASS_ENABLE, FB_CONFIG0_DC_BYPASS) + +#define RV_CONFIG0_DC_BYPASS_DISABLE \ + RV(FV_CONFIG0_DC_BYPASS_DISABLE, FB_CONFIG0_DC_BYPASS) + +#define RV_CONFIG0_SD_FORCE_ON_ENABLE \ + RV(FV_CONFIG0_SD_FORCE_ON_ENABLE, FB_CONFIG0_SD_FORCE_ON) + +#define RV_CONFIG0_SD_FORCE_ON_DISABLE \ + RV(FV_CONFIG0_SD_FORCE_ON_DISABLE, FB_CONFIG0_SD_FORCE_ON) + + +/****************************** + * R_CONFIG1 (0x20) * + ******************************/ + +/* Field Offsets */ +#define FB_CONFIG1_EQ2_EN 7 +#define FB_CONFIG1_EQ2_BE 4 +#define FB_CONFIG1_EQ1_EN 3 +#define FB_CONFIG1_EQ1_BE 0 + +/* Field Masks */ +#define FM_CONFIG1_EQ2_EN 0X1 +#define FM_CONFIG1_EQ2_BE 0X7 +#define FM_CONFIG1_EQ1_EN 0X1 +#define FM_CONFIG1_EQ1_BE 0X7 + +/* Field Values */ +#define FV_CONFIG1_EQ2_EN_ENABLE 0x1 +#define FV_CONFIG1_EQ2_EN_DISABLE 0x0 +#define FV_CONFIG1_EQ2_BE_PRE 0x0 +#define FV_CONFIG1_EQ2_BE_PRE_EQ_0 0x1 +#define FV_CONFIG1_EQ2_BE_PRE_EQ0_1 0x2 +#define FV_CONFIG1_EQ2_BE_PRE_EQ0_2 0x3 +#define FV_CONFIG1_EQ2_BE_PRE_EQ0_3 0x4 +#define FV_CONFIG1_EQ2_BE_PRE_EQ0_4 0x5 +#define FV_CONFIG1_EQ2_BE_PRE_EQ0_5 0x6 +#define FV_CONFIG1_EQ1_EN_ENABLE 0x1 +#define FV_CONFIG1_EQ1_EN_DISABLE 0x0 +#define FV_CONFIG1_EQ1_BE_PRE 0x0 +#define FV_CONFIG1_EQ1_BE_PRE_EQ_0 0x1 +#define FV_CONFIG1_EQ1_BE_PRE_EQ0_1 0x2 +#define FV_CONFIG1_EQ1_BE_PRE_EQ0_2 0x3 +#define FV_CONFIG1_EQ1_BE_PRE_EQ0_3 0x4 +#define FV_CONFIG1_EQ1_BE_PRE_EQ0_4 0x5 +#define FV_CONFIG1_EQ1_BE_PRE_EQ0_5 0x6 + +/* Register Masks */ +#define RM_CONFIG1_EQ2_EN \ + RM(FM_CONFIG1_EQ2_EN, FB_CONFIG1_EQ2_EN) + +#define RM_CONFIG1_EQ2_BE \ + RM(FM_CONFIG1_EQ2_BE, FB_CONFIG1_EQ2_BE) + +#define RM_CONFIG1_EQ1_EN \ + RM(FM_CONFIG1_EQ1_EN, FB_CONFIG1_EQ1_EN) + +#define RM_CONFIG1_EQ1_BE \ + RM(FM_CONFIG1_EQ1_BE, FB_CONFIG1_EQ1_BE) + + +/* Register Values */ +#define RV_CONFIG1_EQ2_EN_ENABLE \ + RV(FV_CONFIG1_EQ2_EN_ENABLE, FB_CONFIG1_EQ2_EN) + +#define RV_CONFIG1_EQ2_EN_DISABLE \ + RV(FV_CONFIG1_EQ2_EN_DISABLE, FB_CONFIG1_EQ2_EN) + +#define RV_CONFIG1_EQ2_BE_PRE \ + RV(FV_CONFIG1_EQ2_BE_PRE, FB_CONFIG1_EQ2_BE) + +#define RV_CONFIG1_EQ2_BE_PRE_EQ_0 \ + RV(FV_CONFIG1_EQ2_BE_PRE_EQ_0, FB_CONFIG1_EQ2_BE) + +#define RV_CONFIG1_EQ2_BE_PRE_EQ0_1 \ + RV(FV_CONFIG1_EQ2_BE_PRE_EQ0_1, FB_CONFIG1_EQ2_BE) + +#define RV_CONFIG1_EQ2_BE_PRE_EQ0_2 \ + RV(FV_CONFIG1_EQ2_BE_PRE_EQ0_2, FB_CONFIG1_EQ2_BE) + +#define RV_CONFIG1_EQ2_BE_PRE_EQ0_3 \ + RV(FV_CONFIG1_EQ2_BE_PRE_EQ0_3, FB_CONFIG1_EQ2_BE) + +#define RV_CONFIG1_EQ2_BE_PRE_EQ0_4 \ + RV(FV_CONFIG1_EQ2_BE_PRE_EQ0_4, FB_CONFIG1_EQ2_BE) + +#define RV_CONFIG1_EQ2_BE_PRE_EQ0_5 \ + RV(FV_CONFIG1_EQ2_BE_PRE_EQ0_5, FB_CONFIG1_EQ2_BE) + +#define RV_CONFIG1_EQ1_EN_ENABLE \ + RV(FV_CONFIG1_EQ1_EN_ENABLE, FB_CONFIG1_EQ1_EN) + +#define RV_CONFIG1_EQ1_EN_DISABLE \ + RV(FV_CONFIG1_EQ1_EN_DISABLE, FB_CONFIG1_EQ1_EN) + +#define RV_CONFIG1_EQ1_BE_PRE \ + RV(FV_CONFIG1_EQ1_BE_PRE, FB_CONFIG1_EQ1_BE) + +#define RV_CONFIG1_EQ1_BE_PRE_EQ_0 \ + RV(FV_CONFIG1_EQ1_BE_PRE_EQ_0, FB_CONFIG1_EQ1_BE) + +#define RV_CONFIG1_EQ1_BE_PRE_EQ0_1 \ + RV(FV_CONFIG1_EQ1_BE_PRE_EQ0_1, FB_CONFIG1_EQ1_BE) + +#define RV_CONFIG1_EQ1_BE_PRE_EQ0_2 \ + RV(FV_CONFIG1_EQ1_BE_PRE_EQ0_2, FB_CONFIG1_EQ1_BE) + +#define RV_CONFIG1_EQ1_BE_PRE_EQ0_3 \ + RV(FV_CONFIG1_EQ1_BE_PRE_EQ0_3, FB_CONFIG1_EQ1_BE) + +#define RV_CONFIG1_EQ1_BE_PRE_EQ0_4 \ + RV(FV_CONFIG1_EQ1_BE_PRE_EQ0_4, FB_CONFIG1_EQ1_BE) + +#define RV_CONFIG1_EQ1_BE_PRE_EQ0_5 \ + RV(FV_CONFIG1_EQ1_BE_PRE_EQ0_5, FB_CONFIG1_EQ1_BE) + + +/****************************** + * R_DMICCTL (0x24) * + ******************************/ + +/* Field Offsets */ +#define FB_DMICCTL_DMICEN 7 +#define FB_DMICCTL_DMONO 4 +#define FB_DMICCTL_DMPHADJ 2 +#define FB_DMICCTL_DMRATE 0 + +/* Field Masks */ +#define FM_DMICCTL_DMICEN 0X1 +#define FM_DMICCTL_DMONO 0X1 +#define FM_DMICCTL_DMPHADJ 0X3 +#define FM_DMICCTL_DMRATE 0X3 + +/* Field Values */ +#define FV_DMICCTL_DMICEN_ENABLE 0x1 +#define FV_DMICCTL_DMICEN_DISABLE 0x0 +#define FV_DMICCTL_DMONO_STEREO 0x0 +#define FV_DMICCTL_DMONO_MONO 0x1 + +/* Register Masks */ +#define RM_DMICCTL_DMICEN \ + RM(FM_DMICCTL_DMICEN, FB_DMICCTL_DMICEN) + +#define RM_DMICCTL_DMONO \ + RM(FM_DMICCTL_DMONO, FB_DMICCTL_DMONO) + +#define RM_DMICCTL_DMPHADJ \ + RM(FM_DMICCTL_DMPHADJ, FB_DMICCTL_DMPHADJ) + +#define RM_DMICCTL_DMRATE \ + RM(FM_DMICCTL_DMRATE, FB_DMICCTL_DMRATE) + + +/* Register Values */ +#define RV_DMICCTL_DMICEN_ENABLE \ + RV(FV_DMICCTL_DMICEN_ENABLE, FB_DMICCTL_DMICEN) + +#define RV_DMICCTL_DMICEN_DISABLE \ + RV(FV_DMICCTL_DMICEN_DISABLE, FB_DMICCTL_DMICEN) + +#define RV_DMICCTL_DMONO_STEREO \ + RV(FV_DMICCTL_DMONO_STEREO, FB_DMICCTL_DMONO) + +#define RV_DMICCTL_DMONO_MONO \ + RV(FV_DMICCTL_DMONO_MONO, FB_DMICCTL_DMONO) + + +/***************************** + * R_CLECTL (0x25) * + *****************************/ + +/* Field Offsets */ +#define FB_CLECTL_LVL_MODE 4 +#define FB_CLECTL_WINDOWSEL 3 +#define FB_CLECTL_EXP_EN 2 +#define FB_CLECTL_LIMIT_EN 1 +#define FB_CLECTL_COMP_EN 0 + +/* Field Masks */ +#define FM_CLECTL_LVL_MODE 0X1 +#define FM_CLECTL_WINDOWSEL 0X1 +#define FM_CLECTL_EXP_EN 0X1 +#define FM_CLECTL_LIMIT_EN 0X1 +#define FM_CLECTL_COMP_EN 0X1 + +/* Field Values */ +#define FV_CLECTL_LVL_MODE_AVG 0x0 +#define FV_CLECTL_LVL_MODE_PEAK 0x1 +#define FV_CLECTL_WINDOWSEL_512 0x0 +#define FV_CLECTL_WINDOWSEL_64 0x1 +#define FV_CLECTL_EXP_EN_ENABLE 0x1 +#define FV_CLECTL_EXP_EN_DISABLE 0x0 +#define FV_CLECTL_LIMIT_EN_ENABLE 0x1 +#define FV_CLECTL_LIMIT_EN_DISABLE 0x0 +#define FV_CLECTL_COMP_EN_ENABLE 0x1 +#define FV_CLECTL_COMP_EN_DISABLE 0x0 + +/* Register Masks */ +#define RM_CLECTL_LVL_MODE \ + RM(FM_CLECTL_LVL_MODE, FB_CLECTL_LVL_MODE) + +#define RM_CLECTL_WINDOWSEL \ + RM(FM_CLECTL_WINDOWSEL, FB_CLECTL_WINDOWSEL) + +#define RM_CLECTL_EXP_EN \ + RM(FM_CLECTL_EXP_EN, FB_CLECTL_EXP_EN) + +#define RM_CLECTL_LIMIT_EN \ + RM(FM_CLECTL_LIMIT_EN, FB_CLECTL_LIMIT_EN) + +#define RM_CLECTL_COMP_EN \ + RM(FM_CLECTL_COMP_EN, FB_CLECTL_COMP_EN) + + +/* Register Values */ +#define RV_CLECTL_LVL_MODE_AVG \ + RV(FV_CLECTL_LVL_MODE_AVG, FB_CLECTL_LVL_MODE) + +#define RV_CLECTL_LVL_MODE_PEAK \ + RV(FV_CLECTL_LVL_MODE_PEAK, FB_CLECTL_LVL_MODE) + +#define RV_CLECTL_WINDOWSEL_512 \ + RV(FV_CLECTL_WINDOWSEL_512, FB_CLECTL_WINDOWSEL) + +#define RV_CLECTL_WINDOWSEL_64 \ + RV(FV_CLECTL_WINDOWSEL_64, FB_CLECTL_WINDOWSEL) + +#define RV_CLECTL_EXP_EN_ENABLE \ + RV(FV_CLECTL_EXP_EN_ENABLE, FB_CLECTL_EXP_EN) + +#define RV_CLECTL_EXP_EN_DISABLE \ + RV(FV_CLECTL_EXP_EN_DISABLE, FB_CLECTL_EXP_EN) + +#define RV_CLECTL_LIMIT_EN_ENABLE \ + RV(FV_CLECTL_LIMIT_EN_ENABLE, FB_CLECTL_LIMIT_EN) + +#define RV_CLECTL_LIMIT_EN_DISABLE \ + RV(FV_CLECTL_LIMIT_EN_DISABLE, FB_CLECTL_LIMIT_EN) + +#define RV_CLECTL_COMP_EN_ENABLE \ + RV(FV_CLECTL_COMP_EN_ENABLE, FB_CLECTL_COMP_EN) + +#define RV_CLECTL_COMP_EN_DISABLE \ + RV(FV_CLECTL_COMP_EN_DISABLE, FB_CLECTL_COMP_EN) + + +/***************************** + * R_MUGAIN (0x26) * + *****************************/ + +/* Field Offsets */ +#define FB_MUGAIN_CLEMUG 0 + +/* Field Masks */ +#define FM_MUGAIN_CLEMUG 0X1F + +/* Field Values */ +#define FV_MUGAIN_CLEMUG_46PT5DB 0x1F +#define FV_MUGAIN_CLEMUG_0DB 0x0 + +/* Register Masks */ +#define RM_MUGAIN_CLEMUG \ + RM(FM_MUGAIN_CLEMUG, FB_MUGAIN_CLEMUG) + + +/* Register Values */ +#define RV_MUGAIN_CLEMUG_46PT5DB \ + RV(FV_MUGAIN_CLEMUG_46PT5DB, FB_MUGAIN_CLEMUG) + +#define RV_MUGAIN_CLEMUG_0DB \ + RV(FV_MUGAIN_CLEMUG_0DB, FB_MUGAIN_CLEMUG) + + +/***************************** + * R_COMPTH (0x27) * + *****************************/ + +/* Field Offsets */ +#define FB_COMPTH 0 + +/* Field Masks */ +#define FM_COMPTH 0XFF + +/* Field Values */ +#define FV_COMPTH_0DB 0xFF +#define FV_COMPTH_N95PT625DB 0x0 + +/* Register Masks */ +#define RM_COMPTH RM(FM_COMPTH, FB_COMPTH) + +/* Register Values */ +#define RV_COMPTH_0DB RV(FV_COMPTH_0DB, FB_COMPTH) +#define RV_COMPTH_N95PT625DB \ + RV(FV_COMPTH_N95PT625DB, FB_COMPTH) + + +/***************************** + * R_CMPRAT (0x28) * + *****************************/ + +/* Field Offsets */ +#define FB_CMPRAT 0 + +/* Field Masks */ +#define FM_CMPRAT 0X1F + +/* Register Masks */ +#define RM_CMPRAT RM(FM_CMPRAT, FB_CMPRAT) + +/****************************** + * R_CATKTCL (0x29) * + ******************************/ + +/* Field Offsets */ +#define FB_CATKTCL 0 + +/* Field Masks */ +#define FM_CATKTCL 0XFF + +/* Register Masks */ +#define RM_CATKTCL RM(FM_CATKTCL, FB_CATKTCL) + +/****************************** + * R_CATKTCH (0x2A) * + ******************************/ + +/* Field Offsets */ +#define FB_CATKTCH 0 + +/* Field Masks */ +#define FM_CATKTCH 0XFF + +/* Register Masks */ +#define RM_CATKTCH RM(FM_CATKTCH, FB_CATKTCH) + +/****************************** + * R_CRELTCL (0x2B) * + ******************************/ + +/* Field Offsets */ +#define FB_CRELTCL 0 + +/* Field Masks */ +#define FM_CRELTCL 0XFF + +/* Register Masks */ +#define RM_CRELTCL RM(FM_CRELTCL, FB_CRELTCL) + +/****************************** + * R_CRELTCH (0x2C) * + ******************************/ + +/* Field Offsets */ +#define FB_CRELTCH 0 + +/* Field Masks */ +#define FM_CRELTCH 0XFF + +/* Register Masks */ +#define RM_CRELTCH RM(FM_CRELTCH, FB_CRELTCH) + +/**************************** + * R_LIMTH (0x2D) * + ****************************/ + +/* Field Offsets */ +#define FB_LIMTH 0 + +/* Field Masks */ +#define FM_LIMTH 0XFF + +/* Field Values */ +#define FV_LIMTH_0DB 0xFF +#define FV_LIMTH_N95PT625DB 0x0 + +/* Register Masks */ +#define RM_LIMTH RM(FM_LIMTH, FB_LIMTH) + +/* Register Values */ +#define RV_LIMTH_0DB RV(FV_LIMTH_0DB, FB_LIMTH) +#define RV_LIMTH_N95PT625DB RV(FV_LIMTH_N95PT625DB, FB_LIMTH) + +/***************************** + * R_LIMTGT (0x2E) * + *****************************/ + +/* Field Offsets */ +#define FB_LIMTGT 0 + +/* Field Masks */ +#define FM_LIMTGT 0XFF + +/* Field Values */ +#define FV_LIMTGT_0DB 0xFF +#define FV_LIMTGT_N95PT625DB 0x0 + +/* Register Masks */ +#define RM_LIMTGT RM(FM_LIMTGT, FB_LIMTGT) + +/* Register Values */ +#define RV_LIMTGT_0DB RV(FV_LIMTGT_0DB, FB_LIMTGT) +#define RV_LIMTGT_N95PT625DB \ + RV(FV_LIMTGT_N95PT625DB, FB_LIMTGT) + + +/****************************** + * R_LATKTCL (0x2F) * + ******************************/ + +/* Field Offsets */ +#define FB_LATKTCL 0 + +/* Field Masks */ +#define FM_LATKTCL 0XFF + +/* Register Masks */ +#define RM_LATKTCL RM(FM_LATKTCL, FB_LATKTCL) + +/****************************** + * R_LATKTCH (0x30) * + ******************************/ + +/* Field Offsets */ +#define FB_LATKTCH 0 + +/* Field Masks */ +#define FM_LATKTCH 0XFF + +/* Register Masks */ +#define RM_LATKTCH RM(FM_LATKTCH, FB_LATKTCH) + +/****************************** + * R_LRELTCL (0x31) * + ******************************/ + +/* Field Offsets */ +#define FB_LRELTCL 0 + +/* Field Masks */ +#define FM_LRELTCL 0XFF + +/* Register Masks */ +#define RM_LRELTCL RM(FM_LRELTCL, FB_LRELTCL) + +/****************************** + * R_LRELTCH (0x32) * + ******************************/ + +/* Field Offsets */ +#define FB_LRELTCH 0 + +/* Field Masks */ +#define FM_LRELTCH 0XFF + +/* Register Masks */ +#define RM_LRELTCH RM(FM_LRELTCH, FB_LRELTCH) + +/**************************** + * R_EXPTH (0x33) * + ****************************/ + +/* Field Offsets */ +#define FB_EXPTH 0 + +/* Field Masks */ +#define FM_EXPTH 0XFF + +/* Field Values */ +#define FV_EXPTH_0DB 0xFF +#define FV_EXPTH_N95PT625DB 0x0 + +/* Register Masks */ +#define RM_EXPTH RM(FM_EXPTH, FB_EXPTH) + +/* Register Values */ +#define RV_EXPTH_0DB RV(FV_EXPTH_0DB, FB_EXPTH) +#define RV_EXPTH_N95PT625DB RV(FV_EXPTH_N95PT625DB, FB_EXPTH) + +/***************************** + * R_EXPRAT (0x34) * + *****************************/ + +/* Field Offsets */ +#define FB_EXPRAT 0 + +/* Field Masks */ +#define FM_EXPRAT 0X7 + +/* Register Masks */ +#define RM_EXPRAT RM(FM_EXPRAT, FB_EXPRAT) + +/****************************** + * R_XATKTCL (0x35) * + ******************************/ + +/* Field Offsets */ +#define FB_XATKTCL 0 + +/* Field Masks */ +#define FM_XATKTCL 0XFF + +/* Register Masks */ +#define RM_XATKTCL RM(FM_XATKTCL, FB_XATKTCL) + +/****************************** + * R_XATKTCH (0x36) * + ******************************/ + +/* Field Offsets */ +#define FB_XATKTCH 0 + +/* Field Masks */ +#define FM_XATKTCH 0XFF + +/* Register Masks */ +#define RM_XATKTCH RM(FM_XATKTCH, FB_XATKTCH) + +/****************************** + * R_XRELTCL (0x37) * + ******************************/ + +/* Field Offsets */ +#define FB_XRELTCL 0 + +/* Field Masks */ +#define FM_XRELTCL 0XFF + +/* Register Masks */ +#define RM_XRELTCL RM(FM_XRELTCL, FB_XRELTCL) + +/****************************** + * R_XRELTCH (0x38) * + ******************************/ + +/* Field Offsets */ +#define FB_XRELTCH 0 + +/* Field Masks */ +#define FM_XRELTCH 0XFF + +/* Register Masks */ +#define RM_XRELTCH RM(FM_XRELTCH, FB_XRELTCH) + +/**************************** + * R_FXCTL (0x39) * + ****************************/ + +/* Field Offsets */ +#define FB_FXCTL_3DEN 4 +#define FB_FXCTL_TEEN 3 +#define FB_FXCTL_TNLFBYPASS 2 +#define FB_FXCTL_BEEN 1 +#define FB_FXCTL_BNLFBYPASS 0 + +/* Field Masks */ +#define FM_FXCTL_3DEN 0X1 +#define FM_FXCTL_TEEN 0X1 +#define FM_FXCTL_TNLFBYPASS 0X1 +#define FM_FXCTL_BEEN 0X1 +#define FM_FXCTL_BNLFBYPASS 0X1 + +/* Field Values */ +#define FV_FXCTL_3DEN_ENABLE 0x1 +#define FV_FXCTL_3DEN_DISABLE 0x0 +#define FV_FXCTL_TEEN_ENABLE 0x1 +#define FV_FXCTL_TEEN_DISABLE 0x0 +#define FV_FXCTL_TNLFBYPASS_ENABLE 0x1 +#define FV_FXCTL_TNLFBYPASS_DISABLE 0x0 +#define FV_FXCTL_BEEN_ENABLE 0x1 +#define FV_FXCTL_BEEN_DISABLE 0x0 +#define FV_FXCTL_BNLFBYPASS_ENABLE 0x1 +#define FV_FXCTL_BNLFBYPASS_DISABLE 0x0 + +/* Register Masks */ +#define RM_FXCTL_3DEN RM(FM_FXCTL_3DEN, FB_FXCTL_3DEN) +#define RM_FXCTL_TEEN RM(FM_FXCTL_TEEN, FB_FXCTL_TEEN) +#define RM_FXCTL_TNLFBYPASS \ + RM(FM_FXCTL_TNLFBYPASS, FB_FXCTL_TNLFBYPASS) + +#define RM_FXCTL_BEEN RM(FM_FXCTL_BEEN, FB_FXCTL_BEEN) +#define RM_FXCTL_BNLFBYPASS \ + RM(FM_FXCTL_BNLFBYPASS, FB_FXCTL_BNLFBYPASS) + + +/* Register Values */ +#define RV_FXCTL_3DEN_ENABLE \ + RV(FV_FXCTL_3DEN_ENABLE, FB_FXCTL_3DEN) + +#define RV_FXCTL_3DEN_DISABLE \ + RV(FV_FXCTL_3DEN_DISABLE, FB_FXCTL_3DEN) + +#define RV_FXCTL_TEEN_ENABLE \ + RV(FV_FXCTL_TEEN_ENABLE, FB_FXCTL_TEEN) + +#define RV_FXCTL_TEEN_DISABLE \ + RV(FV_FXCTL_TEEN_DISABLE, FB_FXCTL_TEEN) + +#define RV_FXCTL_TNLFBYPASS_ENABLE \ + RV(FV_FXCTL_TNLFBYPASS_ENABLE, FB_FXCTL_TNLFBYPASS) + +#define RV_FXCTL_TNLFBYPASS_DISABLE \ + RV(FV_FXCTL_TNLFBYPASS_DISABLE, FB_FXCTL_TNLFBYPASS) + +#define RV_FXCTL_BEEN_ENABLE \ + RV(FV_FXCTL_BEEN_ENABLE, FB_FXCTL_BEEN) + +#define RV_FXCTL_BEEN_DISABLE \ + RV(FV_FXCTL_BEEN_DISABLE, FB_FXCTL_BEEN) + +#define RV_FXCTL_BNLFBYPASS_ENABLE \ + RV(FV_FXCTL_BNLFBYPASS_ENABLE, FB_FXCTL_BNLFBYPASS) + +#define RV_FXCTL_BNLFBYPASS_DISABLE \ + RV(FV_FXCTL_BNLFBYPASS_DISABLE, FB_FXCTL_BNLFBYPASS) + + +/******************************* + * R_DACCRWRL (0x3A) * + *******************************/ + +/* Field Offsets */ +#define FB_DACCRWRL_DACCRWDL 0 + +/* Field Masks */ +#define FM_DACCRWRL_DACCRWDL 0XFF + +/* Register Masks */ +#define RM_DACCRWRL_DACCRWDL \ + RM(FM_DACCRWRL_DACCRWDL, FB_DACCRWRL_DACCRWDL) + + +/******************************* + * R_DACCRWRM (0x3B) * + *******************************/ + +/* Field Offsets */ +#define FB_DACCRWRM_DACCRWDM 0 + +/* Field Masks */ +#define FM_DACCRWRM_DACCRWDM 0XFF + +/* Register Masks */ +#define RM_DACCRWRM_DACCRWDM \ + RM(FM_DACCRWRM_DACCRWDM, FB_DACCRWRM_DACCRWDM) + + +/******************************* + * R_DACCRWRH (0x3C) * + *******************************/ + +/* Field Offsets */ +#define FB_DACCRWRH_DACCRWDH 0 + +/* Field Masks */ +#define FM_DACCRWRH_DACCRWDH 0XFF + +/* Register Masks */ +#define RM_DACCRWRH_DACCRWDH \ + RM(FM_DACCRWRH_DACCRWDH, FB_DACCRWRH_DACCRWDH) + + +/******************************* + * R_DACCRRDL (0x3D) * + *******************************/ + +/* Field Offsets */ +#define FB_DACCRRDL 0 + +/* Field Masks */ +#define FM_DACCRRDL 0XFF + +/* Register Masks */ +#define RM_DACCRRDL RM(FM_DACCRRDL, FB_DACCRRDL) + +/******************************* + * R_DACCRRDM (0x3E) * + *******************************/ + +/* Field Offsets */ +#define FB_DACCRRDM 0 + +/* Field Masks */ +#define FM_DACCRRDM 0XFF + +/* Register Masks */ +#define RM_DACCRRDM RM(FM_DACCRRDM, FB_DACCRRDM) + +/******************************* + * R_DACCRRDH (0x3F) * + *******************************/ + +/* Field Offsets */ +#define FB_DACCRRDH 0 + +/* Field Masks */ +#define FM_DACCRRDH 0XFF + +/* Register Masks */ +#define RM_DACCRRDH RM(FM_DACCRRDH, FB_DACCRRDH) + +/******************************** + * R_DACCRADDR (0x40) * + ********************************/ + +/* Field Offsets */ +#define FB_DACCRADDR_DACCRADD 0 + +/* Field Masks */ +#define FM_DACCRADDR_DACCRADD 0XFF + +/* Register Masks */ +#define RM_DACCRADDR_DACCRADD \ + RM(FM_DACCRADDR_DACCRADD, FB_DACCRADDR_DACCRADD) + + +/****************************** + * R_DCOFSEL (0x41) * + ******************************/ + +/* Field Offsets */ +#define FB_DCOFSEL_DC_COEF_SEL 0 + +/* Field Masks */ +#define FM_DCOFSEL_DC_COEF_SEL 0X7 + +/* Field Values */ +#define FV_DCOFSEL_DC_COEF_SEL_2_N8 0x0 +#define FV_DCOFSEL_DC_COEF_SEL_2_N9 0x1 +#define FV_DCOFSEL_DC_COEF_SEL_2_N10 0x2 +#define FV_DCOFSEL_DC_COEF_SEL_2_N11 0x3 +#define FV_DCOFSEL_DC_COEF_SEL_2_N12 0x4 +#define FV_DCOFSEL_DC_COEF_SEL_2_N13 0x5 +#define FV_DCOFSEL_DC_COEF_SEL_2_N14 0x6 +#define FV_DCOFSEL_DC_COEF_SEL_2_N15 0x7 + +/* Register Masks */ +#define RM_DCOFSEL_DC_COEF_SEL \ + RM(FM_DCOFSEL_DC_COEF_SEL, FB_DCOFSEL_DC_COEF_SEL) + + +/* Register Values */ +#define RV_DCOFSEL_DC_COEF_SEL_2_N8 \ + RV(FV_DCOFSEL_DC_COEF_SEL_2_N8, FB_DCOFSEL_DC_COEF_SEL) + +#define RV_DCOFSEL_DC_COEF_SEL_2_N9 \ + RV(FV_DCOFSEL_DC_COEF_SEL_2_N9, FB_DCOFSEL_DC_COEF_SEL) + +#define RV_DCOFSEL_DC_COEF_SEL_2_N10 \ + RV(FV_DCOFSEL_DC_COEF_SEL_2_N10, FB_DCOFSEL_DC_COEF_SEL) + +#define RV_DCOFSEL_DC_COEF_SEL_2_N11 \ + RV(FV_DCOFSEL_DC_COEF_SEL_2_N11, FB_DCOFSEL_DC_COEF_SEL) + +#define RV_DCOFSEL_DC_COEF_SEL_2_N12 \ + RV(FV_DCOFSEL_DC_COEF_SEL_2_N12, FB_DCOFSEL_DC_COEF_SEL) + +#define RV_DCOFSEL_DC_COEF_SEL_2_N13 \ + RV(FV_DCOFSEL_DC_COEF_SEL_2_N13, FB_DCOFSEL_DC_COEF_SEL) + +#define RV_DCOFSEL_DC_COEF_SEL_2_N14 \ + RV(FV_DCOFSEL_DC_COEF_SEL_2_N14, FB_DCOFSEL_DC_COEF_SEL) + +#define RV_DCOFSEL_DC_COEF_SEL_2_N15 \ + RV(FV_DCOFSEL_DC_COEF_SEL_2_N15, FB_DCOFSEL_DC_COEF_SEL) + + +/****************************** + * R_PLLCTL9 (0x4E) * + ******************************/ + +/* Field Offsets */ +#define FB_PLLCTL9_REFDIV_PLL1 0 + +/* Field Masks */ +#define FM_PLLCTL9_REFDIV_PLL1 0XFF + +/* Register Masks */ +#define RM_PLLCTL9_REFDIV_PLL1 \ + RM(FM_PLLCTL9_REFDIV_PLL1, FB_PLLCTL9_REFDIV_PLL1) + + +/****************************** + * R_PLLCTLA (0x4F) * + ******************************/ + +/* Field Offsets */ +#define FB_PLLCTLA_OUTDIV_PLL1 0 + +/* Field Masks */ +#define FM_PLLCTLA_OUTDIV_PLL1 0XFF + +/* Register Masks */ +#define RM_PLLCTLA_OUTDIV_PLL1 \ + RM(FM_PLLCTLA_OUTDIV_PLL1, FB_PLLCTLA_OUTDIV_PLL1) + + +/****************************** + * R_PLLCTLB (0x50) * + ******************************/ + +/* Field Offsets */ +#define FB_PLLCTLB_FBDIV_PLL1L 0 + +/* Field Masks */ +#define FM_PLLCTLB_FBDIV_PLL1L 0XFF + +/* Register Masks */ +#define RM_PLLCTLB_FBDIV_PLL1L \ + RM(FM_PLLCTLB_FBDIV_PLL1L, FB_PLLCTLB_FBDIV_PLL1L) + + +/****************************** + * R_PLLCTLC (0x51) * + ******************************/ + +/* Field Offsets */ +#define FB_PLLCTLC_FBDIV_PLL1H 0 + +/* Field Masks */ +#define FM_PLLCTLC_FBDIV_PLL1H 0X7 + +/* Register Masks */ +#define RM_PLLCTLC_FBDIV_PLL1H \ + RM(FM_PLLCTLC_FBDIV_PLL1H, FB_PLLCTLC_FBDIV_PLL1H) + + +/****************************** + * R_PLLCTLD (0x52) * + ******************************/ + +/* Field Offsets */ +#define FB_PLLCTLD_RZ_PLL1 3 +#define FB_PLLCTLD_CP_PLL1 0 + +/* Field Masks */ +#define FM_PLLCTLD_RZ_PLL1 0X7 +#define FM_PLLCTLD_CP_PLL1 0X7 + +/* Register Masks */ +#define RM_PLLCTLD_RZ_PLL1 \ + RM(FM_PLLCTLD_RZ_PLL1, FB_PLLCTLD_RZ_PLL1) + +#define RM_PLLCTLD_CP_PLL1 \ + RM(FM_PLLCTLD_CP_PLL1, FB_PLLCTLD_CP_PLL1) + + +/****************************** + * R_PLLCTLE (0x53) * + ******************************/ + +/* Field Offsets */ +#define FB_PLLCTLE_REFDIV_PLL2 0 + +/* Field Masks */ +#define FM_PLLCTLE_REFDIV_PLL2 0XFF + +/* Register Masks */ +#define RM_PLLCTLE_REFDIV_PLL2 \ + RM(FM_PLLCTLE_REFDIV_PLL2, FB_PLLCTLE_REFDIV_PLL2) + + +/****************************** + * R_PLLCTLF (0x54) * + ******************************/ + +/* Field Offsets */ +#define FB_PLLCTLF_OUTDIV_PLL2 0 + +/* Field Masks */ +#define FM_PLLCTLF_OUTDIV_PLL2 0XFF + +/* Register Masks */ +#define RM_PLLCTLF_OUTDIV_PLL2 \ + RM(FM_PLLCTLF_OUTDIV_PLL2, FB_PLLCTLF_OUTDIV_PLL2) + + +/******************************* + * R_PLLCTL10 (0x55) * + *******************************/ + +/* Field Offsets */ +#define FB_PLLCTL10_FBDIV_PLL2L 0 + +/* Field Masks */ +#define FM_PLLCTL10_FBDIV_PLL2L 0XFF + +/* Register Masks */ +#define RM_PLLCTL10_FBDIV_PLL2L \ + RM(FM_PLLCTL10_FBDIV_PLL2L, FB_PLLCTL10_FBDIV_PLL2L) + + +/******************************* + * R_PLLCTL11 (0x56) * + *******************************/ + +/* Field Offsets */ +#define FB_PLLCTL11_FBDIV_PLL2H 0 + +/* Field Masks */ +#define FM_PLLCTL11_FBDIV_PLL2H 0X7 + +/* Register Masks */ +#define RM_PLLCTL11_FBDIV_PLL2H \ + RM(FM_PLLCTL11_FBDIV_PLL2H, FB_PLLCTL11_FBDIV_PLL2H) + + +/******************************* + * R_PLLCTL12 (0x57) * + *******************************/ + +/* Field Offsets */ +#define FB_PLLCTL12_RZ_PLL2 3 +#define FB_PLLCTL12_CP_PLL2 0 + +/* Field Masks */ +#define FM_PLLCTL12_RZ_PLL2 0X7 +#define FM_PLLCTL12_CP_PLL2 0X7 + +/* Register Masks */ +#define RM_PLLCTL12_RZ_PLL2 \ + RM(FM_PLLCTL12_RZ_PLL2, FB_PLLCTL12_RZ_PLL2) + +#define RM_PLLCTL12_CP_PLL2 \ + RM(FM_PLLCTL12_CP_PLL2, FB_PLLCTL12_CP_PLL2) + + +/******************************* + * R_PLLCTL1B (0x60) * + *******************************/ + +/* Field Offsets */ +#define FB_PLLCTL1B_VCOI_PLL2 4 +#define FB_PLLCTL1B_VCOI_PLL1 2 + +/* Field Masks */ +#define FM_PLLCTL1B_VCOI_PLL2 0X3 +#define FM_PLLCTL1B_VCOI_PLL1 0X3 + +/* Register Masks */ +#define RM_PLLCTL1B_VCOI_PLL2 \ + RM(FM_PLLCTL1B_VCOI_PLL2, FB_PLLCTL1B_VCOI_PLL2) + +#define RM_PLLCTL1B_VCOI_PLL1 \ + RM(FM_PLLCTL1B_VCOI_PLL1, FB_PLLCTL1B_VCOI_PLL1) + + +/******************************* + * R_PLLCTL1C (0x61) * + *******************************/ + +/* Field Offsets */ +#define FB_PLLCTL1C_PDB_PLL2 2 +#define FB_PLLCTL1C_PDB_PLL1 1 + +/* Field Masks */ +#define FM_PLLCTL1C_PDB_PLL2 0X1 +#define FM_PLLCTL1C_PDB_PLL1 0X1 + +/* Field Values */ +#define FV_PLLCTL1C_PDB_PLL2_ENABLE 0x1 +#define FV_PLLCTL1C_PDB_PLL2_DISABLE 0x0 +#define FV_PLLCTL1C_PDB_PLL1_ENABLE 0x1 +#define FV_PLLCTL1C_PDB_PLL1_DISABLE 0x0 + +/* Register Masks */ +#define RM_PLLCTL1C_PDB_PLL2 \ + RM(FM_PLLCTL1C_PDB_PLL2, FB_PLLCTL1C_PDB_PLL2) + +#define RM_PLLCTL1C_PDB_PLL1 \ + RM(FM_PLLCTL1C_PDB_PLL1, FB_PLLCTL1C_PDB_PLL1) + + +/* Register Values */ +#define RV_PLLCTL1C_PDB_PLL2_ENABLE \ + RV(FV_PLLCTL1C_PDB_PLL2_ENABLE, FB_PLLCTL1C_PDB_PLL2) + +#define RV_PLLCTL1C_PDB_PLL2_DISABLE \ + RV(FV_PLLCTL1C_PDB_PLL2_DISABLE, FB_PLLCTL1C_PDB_PLL2) + +#define RV_PLLCTL1C_PDB_PLL1_ENABLE \ + RV(FV_PLLCTL1C_PDB_PLL1_ENABLE, FB_PLLCTL1C_PDB_PLL1) + +#define RV_PLLCTL1C_PDB_PLL1_DISABLE \ + RV(FV_PLLCTL1C_PDB_PLL1_DISABLE, FB_PLLCTL1C_PDB_PLL1) + + +/******************************* + * R_TIMEBASE (0x77) * + *******************************/ + +/* Field Offsets */ +#define FB_TIMEBASE_DIVIDER 0 + +/* Field Masks */ +#define FM_TIMEBASE_DIVIDER 0XFF + +/* Register Masks */ +#define RM_TIMEBASE_DIVIDER \ + RM(FM_TIMEBASE_DIVIDER, FB_TIMEBASE_DIVIDER) + + +/***************************** + * R_DEVIDL (0x7D) * + *****************************/ + +/* Field Offsets */ +#define FB_DEVIDL_DIDL 0 + +/* Field Masks */ +#define FM_DEVIDL_DIDL 0XFF + +/* Register Masks */ +#define RM_DEVIDL_DIDL RM(FM_DEVIDL_DIDL, FB_DEVIDL_DIDL) + +/***************************** + * R_DEVIDH (0x7E) * + *****************************/ + +/* Field Offsets */ +#define FB_DEVIDH_DIDH 0 + +/* Field Masks */ +#define FM_DEVIDH_DIDH 0XFF + +/* Register Masks */ +#define RM_DEVIDH_DIDH RM(FM_DEVIDH_DIDH, FB_DEVIDH_DIDH) + +/**************************** + * R_RESET (0x80) * + ****************************/ + +/* Field Offsets */ +#define FB_RESET 0 + +/* Field Masks */ +#define FM_RESET 0XFF + +/* Field Values */ +#define FV_RESET_ENABLE 0x85 + +/* Register Masks */ +#define RM_RESET RM(FM_RESET, FB_RESET) + +/* Register Values */ +#define RV_RESET_ENABLE RV(FV_RESET_ENABLE, FB_RESET) + +/******************************** + * R_DACCRSTAT (0x8A) * + ********************************/ + +/* Field Offsets */ +#define FB_DACCRSTAT_DACCR_BUSY 7 + +/* Field Masks */ +#define FM_DACCRSTAT_DACCR_BUSY 0X1 + +/* Register Masks */ +#define RM_DACCRSTAT_DACCR_BUSY \ + RM(FM_DACCRSTAT_DACCR_BUSY, FB_DACCRSTAT_DACCR_BUSY) + + +/****************************** + * R_PLLCTL0 (0x8E) * + ******************************/ + +/* Field Offsets */ +#define FB_PLLCTL0_PLL2_LOCK 1 +#define FB_PLLCTL0_PLL1_LOCK 0 + +/* Field Masks */ +#define FM_PLLCTL0_PLL2_LOCK 0X1 +#define FM_PLLCTL0_PLL1_LOCK 0X1 + +/* Register Masks */ +#define RM_PLLCTL0_PLL2_LOCK \ + RM(FM_PLLCTL0_PLL2_LOCK, FB_PLLCTL0_PLL2_LOCK) + +#define RM_PLLCTL0_PLL1_LOCK \ + RM(FM_PLLCTL0_PLL1_LOCK, FB_PLLCTL0_PLL1_LOCK) + + +/******************************** + * R_PLLREFSEL (0x8F) * + ********************************/ + +/* Field Offsets */ +#define FB_PLLREFSEL_PLL2_REF_SEL 4 +#define FB_PLLREFSEL_PLL1_REF_SEL 0 + +/* Field Masks */ +#define FM_PLLREFSEL_PLL2_REF_SEL 0X7 +#define FM_PLLREFSEL_PLL1_REF_SEL 0X7 + +/* Field Values */ +#define FV_PLLREFSEL_PLL2_REF_SEL_XTAL_MCLK1 0x0 +#define FV_PLLREFSEL_PLL2_REF_SEL_MCLK2 0x1 +#define FV_PLLREFSEL_PLL1_REF_SEL_XTAL_MCLK1 0x0 +#define FV_PLLREFSEL_PLL1_REF_SEL_MCLK2 0x1 + +/* Register Masks */ +#define RM_PLLREFSEL_PLL2_REF_SEL \ + RM(FM_PLLREFSEL_PLL2_REF_SEL, FB_PLLREFSEL_PLL2_REF_SEL) + +#define RM_PLLREFSEL_PLL1_REF_SEL \ + RM(FM_PLLREFSEL_PLL1_REF_SEL, FB_PLLREFSEL_PLL1_REF_SEL) + + +/* Register Values */ +#define RV_PLLREFSEL_PLL2_REF_SEL_XTAL_MCLK1 \ + RV(FV_PLLREFSEL_PLL2_REF_SEL_XTAL_MCLK1, FB_PLLREFSEL_PLL2_REF_SEL) + +#define RV_PLLREFSEL_PLL2_REF_SEL_MCLK2 \ + RV(FV_PLLREFSEL_PLL2_REF_SEL_MCLK2, FB_PLLREFSEL_PLL2_REF_SEL) + +#define RV_PLLREFSEL_PLL1_REF_SEL_XTAL_MCLK1 \ + RV(FV_PLLREFSEL_PLL1_REF_SEL_XTAL_MCLK1, FB_PLLREFSEL_PLL1_REF_SEL) + +#define RV_PLLREFSEL_PLL1_REF_SEL_MCLK2 \ + RV(FV_PLLREFSEL_PLL1_REF_SEL_MCLK2, FB_PLLREFSEL_PLL1_REF_SEL) + + +/******************************* + * R_DACMBCEN (0xC7) * + *******************************/ + +/* Field Offsets */ +#define FB_DACMBCEN_MBCEN3 2 +#define FB_DACMBCEN_MBCEN2 1 +#define FB_DACMBCEN_MBCEN1 0 + +/* Field Masks */ +#define FM_DACMBCEN_MBCEN3 0X1 +#define FM_DACMBCEN_MBCEN2 0X1 +#define FM_DACMBCEN_MBCEN1 0X1 + +/* Register Masks */ +#define RM_DACMBCEN_MBCEN3 \ + RM(FM_DACMBCEN_MBCEN3, FB_DACMBCEN_MBCEN3) + +#define RM_DACMBCEN_MBCEN2 \ + RM(FM_DACMBCEN_MBCEN2, FB_DACMBCEN_MBCEN2) + +#define RM_DACMBCEN_MBCEN1 \ + RM(FM_DACMBCEN_MBCEN1, FB_DACMBCEN_MBCEN1) + + +/******************************** + * R_DACMBCCTL (0xC8) * + ********************************/ + +/* Field Offsets */ +#define FB_DACMBCCTL_LVLMODE3 5 +#define FB_DACMBCCTL_WINSEL3 4 +#define FB_DACMBCCTL_LVLMODE2 3 +#define FB_DACMBCCTL_WINSEL2 2 +#define FB_DACMBCCTL_LVLMODE1 1 +#define FB_DACMBCCTL_WINSEL1 0 + +/* Field Masks */ +#define FM_DACMBCCTL_LVLMODE3 0X1 +#define FM_DACMBCCTL_WINSEL3 0X1 +#define FM_DACMBCCTL_LVLMODE2 0X1 +#define FM_DACMBCCTL_WINSEL2 0X1 +#define FM_DACMBCCTL_LVLMODE1 0X1 +#define FM_DACMBCCTL_WINSEL1 0X1 + +/* Register Masks */ +#define RM_DACMBCCTL_LVLMODE3 \ + RM(FM_DACMBCCTL_LVLMODE3, FB_DACMBCCTL_LVLMODE3) + +#define RM_DACMBCCTL_WINSEL3 \ + RM(FM_DACMBCCTL_WINSEL3, FB_DACMBCCTL_WINSEL3) + +#define RM_DACMBCCTL_LVLMODE2 \ + RM(FM_DACMBCCTL_LVLMODE2, FB_DACMBCCTL_LVLMODE2) + +#define RM_DACMBCCTL_WINSEL2 \ + RM(FM_DACMBCCTL_WINSEL2, FB_DACMBCCTL_WINSEL2) + +#define RM_DACMBCCTL_LVLMODE1 \ + RM(FM_DACMBCCTL_LVLMODE1, FB_DACMBCCTL_LVLMODE1) + +#define RM_DACMBCCTL_WINSEL1 \ + RM(FM_DACMBCCTL_WINSEL1, FB_DACMBCCTL_WINSEL1) + + +/********************************* + * R_DACMBCMUG1 (0xC9) * + *********************************/ + +/* Field Offsets */ +#define FB_DACMBCMUG1_PHASE 5 +#define FB_DACMBCMUG1_MUGAIN 0 + +/* Field Masks */ +#define FM_DACMBCMUG1_PHASE 0X1 +#define FM_DACMBCMUG1_MUGAIN 0X1F + +/* Register Masks */ +#define RM_DACMBCMUG1_PHASE \ + RM(FM_DACMBCMUG1_PHASE, FB_DACMBCMUG1_PHASE) + +#define RM_DACMBCMUG1_MUGAIN \ + RM(FM_DACMBCMUG1_MUGAIN, FB_DACMBCMUG1_MUGAIN) + + +/********************************* + * R_DACMBCTHR1 (0xCA) * + *********************************/ + +/* Field Offsets */ +#define FB_DACMBCTHR1_THRESH 0 + +/* Field Masks */ +#define FM_DACMBCTHR1_THRESH 0XFF + +/* Register Masks */ +#define RM_DACMBCTHR1_THRESH \ + RM(FM_DACMBCTHR1_THRESH, FB_DACMBCTHR1_THRESH) + + +/********************************* + * R_DACMBCRAT1 (0xCB) * + *********************************/ + +/* Field Offsets */ +#define FB_DACMBCRAT1_RATIO 0 + +/* Field Masks */ +#define FM_DACMBCRAT1_RATIO 0X1F + +/* Register Masks */ +#define RM_DACMBCRAT1_RATIO \ + RM(FM_DACMBCRAT1_RATIO, FB_DACMBCRAT1_RATIO) + + +/********************************** + * R_DACMBCATK1L (0xCC) * + **********************************/ + +/* Field Offsets */ +#define FB_DACMBCATK1L_TCATKL 0 + +/* Field Masks */ +#define FM_DACMBCATK1L_TCATKL 0XFF + +/* Register Masks */ +#define RM_DACMBCATK1L_TCATKL \ + RM(FM_DACMBCATK1L_TCATKL, FB_DACMBCATK1L_TCATKL) + + +/********************************** + * R_DACMBCATK1H (0xCD) * + **********************************/ + +/* Field Offsets */ +#define FB_DACMBCATK1H_TCATKH 0 + +/* Field Masks */ +#define FM_DACMBCATK1H_TCATKH 0XFF + +/* Register Masks */ +#define RM_DACMBCATK1H_TCATKH \ + RM(FM_DACMBCATK1H_TCATKH, FB_DACMBCATK1H_TCATKH) + + +/********************************** + * R_DACMBCREL1L (0xCE) * + **********************************/ + +/* Field Offsets */ +#define FB_DACMBCREL1L_TCRELL 0 + +/* Field Masks */ +#define FM_DACMBCREL1L_TCRELL 0XFF + +/* Register Masks */ +#define RM_DACMBCREL1L_TCRELL \ + RM(FM_DACMBCREL1L_TCRELL, FB_DACMBCREL1L_TCRELL) + + +/********************************** + * R_DACMBCREL1H (0xCF) * + **********************************/ + +/* Field Offsets */ +#define FB_DACMBCREL1H_TCRELH 0 + +/* Field Masks */ +#define FM_DACMBCREL1H_TCRELH 0XFF + +/* Register Masks */ +#define RM_DACMBCREL1H_TCRELH \ + RM(FM_DACMBCREL1H_TCRELH, FB_DACMBCREL1H_TCRELH) + + +/********************************* + * R_DACMBCMUG2 (0xD0) * + *********************************/ + +/* Field Offsets */ +#define FB_DACMBCMUG2_PHASE 5 +#define FB_DACMBCMUG2_MUGAIN 0 + +/* Field Masks */ +#define FM_DACMBCMUG2_PHASE 0X1 +#define FM_DACMBCMUG2_MUGAIN 0X1F + +/* Register Masks */ +#define RM_DACMBCMUG2_PHASE \ + RM(FM_DACMBCMUG2_PHASE, FB_DACMBCMUG2_PHASE) + +#define RM_DACMBCMUG2_MUGAIN \ + RM(FM_DACMBCMUG2_MUGAIN, FB_DACMBCMUG2_MUGAIN) + + +/********************************* + * R_DACMBCTHR2 (0xD1) * + *********************************/ + +/* Field Offsets */ +#define FB_DACMBCTHR2_THRESH 0 + +/* Field Masks */ +#define FM_DACMBCTHR2_THRESH 0XFF + +/* Register Masks */ +#define RM_DACMBCTHR2_THRESH \ + RM(FM_DACMBCTHR2_THRESH, FB_DACMBCTHR2_THRESH) + + +/********************************* + * R_DACMBCRAT2 (0xD2) * + *********************************/ + +/* Field Offsets */ +#define FB_DACMBCRAT2_RATIO 0 + +/* Field Masks */ +#define FM_DACMBCRAT2_RATIO 0X1F + +/* Register Masks */ +#define RM_DACMBCRAT2_RATIO \ + RM(FM_DACMBCRAT2_RATIO, FB_DACMBCRAT2_RATIO) + + +/********************************** + * R_DACMBCATK2L (0xD3) * + **********************************/ + +/* Field Offsets */ +#define FB_DACMBCATK2L_TCATKL 0 + +/* Field Masks */ +#define FM_DACMBCATK2L_TCATKL 0XFF + +/* Register Masks */ +#define RM_DACMBCATK2L_TCATKL \ + RM(FM_DACMBCATK2L_TCATKL, FB_DACMBCATK2L_TCATKL) + + +/********************************** + * R_DACMBCATK2H (0xD4) * + **********************************/ + +/* Field Offsets */ +#define FB_DACMBCATK2H_TCATKH 0 + +/* Field Masks */ +#define FM_DACMBCATK2H_TCATKH 0XFF + +/* Register Masks */ +#define RM_DACMBCATK2H_TCATKH \ + RM(FM_DACMBCATK2H_TCATKH, FB_DACMBCATK2H_TCATKH) + + +/********************************** + * R_DACMBCREL2L (0xD5) * + **********************************/ + +/* Field Offsets */ +#define FB_DACMBCREL2L_TCRELL 0 + +/* Field Masks */ +#define FM_DACMBCREL2L_TCRELL 0XFF + +/* Register Masks */ +#define RM_DACMBCREL2L_TCRELL \ + RM(FM_DACMBCREL2L_TCRELL, FB_DACMBCREL2L_TCRELL) + + +/********************************** + * R_DACMBCREL2H (0xD6) * + **********************************/ + +/* Field Offsets */ +#define FB_DACMBCREL2H_TCRELH 0 + +/* Field Masks */ +#define FM_DACMBCREL2H_TCRELH 0XFF + +/* Register Masks */ +#define RM_DACMBCREL2H_TCRELH \ + RM(FM_DACMBCREL2H_TCRELH, FB_DACMBCREL2H_TCRELH) + + +/********************************* + * R_DACMBCMUG3 (0xD7) * + *********************************/ + +/* Field Offsets */ +#define FB_DACMBCMUG3_PHASE 5 +#define FB_DACMBCMUG3_MUGAIN 0 + +/* Field Masks */ +#define FM_DACMBCMUG3_PHASE 0X1 +#define FM_DACMBCMUG3_MUGAIN 0X1F + +/* Register Masks */ +#define RM_DACMBCMUG3_PHASE \ + RM(FM_DACMBCMUG3_PHASE, FB_DACMBCMUG3_PHASE) + +#define RM_DACMBCMUG3_MUGAIN \ + RM(FM_DACMBCMUG3_MUGAIN, FB_DACMBCMUG3_MUGAIN) + + +/********************************* + * R_DACMBCTHR3 (0xD8) * + *********************************/ + +/* Field Offsets */ +#define FB_DACMBCTHR3_THRESH 0 + +/* Field Masks */ +#define FM_DACMBCTHR3_THRESH 0XFF + +/* Register Masks */ +#define RM_DACMBCTHR3_THRESH \ + RM(FM_DACMBCTHR3_THRESH, FB_DACMBCTHR3_THRESH) + + +/********************************* + * R_DACMBCRAT3 (0xD9) * + *********************************/ + +/* Field Offsets */ +#define FB_DACMBCRAT3_RATIO 0 + +/* Field Masks */ +#define FM_DACMBCRAT3_RATIO 0X1F + +/* Register Masks */ +#define RM_DACMBCRAT3_RATIO \ + RM(FM_DACMBCRAT3_RATIO, FB_DACMBCRAT3_RATIO) + + +/********************************** + * R_DACMBCATK3L (0xDA) * + **********************************/ + +/* Field Offsets */ +#define FB_DACMBCATK3L_TCATKL 0 + +/* Field Masks */ +#define FM_DACMBCATK3L_TCATKL 0XFF + +/* Register Masks */ +#define RM_DACMBCATK3L_TCATKL \ + RM(FM_DACMBCATK3L_TCATKL, FB_DACMBCATK3L_TCATKL) + + +/********************************** + * R_DACMBCATK3H (0xDB) * + **********************************/ + +/* Field Offsets */ +#define FB_DACMBCATK3H_TCATKH 0 + +/* Field Masks */ +#define FM_DACMBCATK3H_TCATKH 0XFF + +/* Register Masks */ +#define RM_DACMBCATK3H_TCATKH \ + RM(FM_DACMBCATK3H_TCATKH, FB_DACMBCATK3H_TCATKH) + + +/********************************** + * R_DACMBCREL3L (0xDC) * + **********************************/ + +/* Field Offsets */ +#define FB_DACMBCREL3L_TCRELL 0 + +/* Field Masks */ +#define FM_DACMBCREL3L_TCRELL 0XFF + +/* Register Masks */ +#define RM_DACMBCREL3L_TCRELL \ + RM(FM_DACMBCREL3L_TCRELL, FB_DACMBCREL3L_TCRELL) + + +/********************************** + * R_DACMBCREL3H (0xDD) * + **********************************/ + +/* Field Offsets */ +#define FB_DACMBCREL3H_TCRELH 0 + +/* Field Masks */ +#define FM_DACMBCREL3H_TCRELH 0XFF + +/* Register Masks */ +#define RM_DACMBCREL3H_TCRELH \ + RM(FM_DACMBCREL3H_TCRELH, FB_DACMBCREL3H_TCRELH) + + +#endif /* __WOOKIE_H__ */ -- cgit v1.2.3 From da911b1f5e98f21b20aa042748dfe73e36322fb1 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Fri, 5 Jan 2018 16:50:08 +0800 Subject: ALSA: hda/realtek - update ALC225 depop optimize Add ALC225 its own depop functions for alc_init and alc_shutup. Add depop optimize step for headset mode functions. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 101 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b2037131eed9..440972975bd4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3166,6 +3166,93 @@ static void alc256_shutup(struct hda_codec *codec) snd_hda_shutup_pins(codec); } +static void alc225_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; + bool hp1_pin_sense, hp2_pin_sense; + + if (!hp_pin) + return; + + msleep(30); + + hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin); + hp2_pin_sense = snd_hda_jack_detect(codec, 0x16); + + if (hp1_pin_sense || hp2_pin_sense) + msleep(2); + + alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ + + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x16, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + + if (hp1_pin_sense || hp2_pin_sense) + msleep(85); + + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x16, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + + if (hp1_pin_sense || hp2_pin_sense) + msleep(100); + + alc_update_coef_idx(codec, 0x4a, 3 << 10, 0); + alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */ +} + +static void alc225_shutup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; + bool hp1_pin_sense, hp2_pin_sense; + + if (!hp_pin) { + alc269_shutup(codec); + return; + } + + /* 3k pull low control for Headset jack. */ + alc_update_coef_idx(codec, 0x4a, 0, 3 << 10); + + hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin); + hp2_pin_sense = snd_hda_jack_detect(codec, 0x16); + + if (hp1_pin_sense || hp2_pin_sense) + msleep(2); + + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x16, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + + if (hp1_pin_sense || hp2_pin_sense) + msleep(85); + + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x16, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + + if (hp1_pin_sense || hp2_pin_sense) + msleep(100); + + alc_auto_setup_eapd(codec, false); + snd_hda_shutup_pins(codec); +} + static void alc_default_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -4569,6 +4656,12 @@ static void alc_determine_headset_type(struct hda_codec *codec) case 0x10ec0225: case 0x10ec0295: case 0x10ec0299: + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + msleep(80); + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + alc_process_coef_fw(codec, alc225_pre_hsmode); alc_update_coef_idx(codec, 0x67, 0xf000, 0x1000); val = alc_read_coef_idx(codec, 0x45); @@ -4588,6 +4681,12 @@ static void alc_determine_headset_type(struct hda_codec *codec) alc_update_coef_idx(codec, 0x4a, 7<<6, 7<<6); alc_update_coef_idx(codec, 0x4a, 3<<4, 3<<4); alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000); + + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + msleep(80); + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); break; case 0x10ec0867: is_ctia = true; @@ -6925,6 +7024,8 @@ static int patch_alc269(struct hda_codec *codec) case 0x10ec0295: case 0x10ec0299: spec->codec_variant = ALC269_TYPE_ALC225; + spec->shutup = alc225_shutup; + spec->init_hook = alc225_init; spec->gen.mixer_nid = 0; /* no loopback on ALC225, ALC295 and ALC299 */ break; case 0x10ec0234: -- cgit v1.2.3 From a5a86a7f87d7b684f0369e1f207bb294cfa58dde Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 7 Jan 2018 09:05:50 -0800 Subject: ASoC: fsl_ssi: Fix build error powerpc:mpc85xx_defconfig fails to build with the following errors. sound/soc/fsl/fsl_dma.c: In function 'fsl_soc_dma_probe': sound/soc/fsl/fsl_dma.c:916:34: error: 'CCSR_SSI_STX0' undeclared sound/soc/fsl/fsl_dma.c:917:34: error: 'CCSR_SSI_SRX0' undeclared Fixes: a818aa5f967b ("ASoC: fsl_ssi: Rename registers and fields macros") Signed-off-by: Guenter Roeck Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 0c11f434a374..8c2981b70f64 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -913,8 +913,8 @@ static int fsl_soc_dma_probe(struct platform_device *pdev) dma->dai.pcm_free = fsl_dma_free_dma_buffers; /* Store the SSI-specific information that we need */ - dma->ssi_stx_phys = res.start + CCSR_SSI_STX0; - dma->ssi_srx_phys = res.start + CCSR_SSI_SRX0; + dma->ssi_stx_phys = res.start + REG_SSI_STX0; + dma->ssi_srx_phys = res.start + REG_SSI_SRX0; iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL); if (iprop) -- cgit v1.2.3 From 3e8052d90d24320a1edb556c20523f3b17195985 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 8 Jan 2018 02:15:01 +0000 Subject: ASoC: mediatek: mt2701: fix return value check in mt2701_afe_pcm_dev_probe() In case of error, the function syscon_node_to_regmap() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Fixes: dfa3cbb83e09 ("ASoC: mediatek: modify MT2701 AFE driver to adapt mfd device") Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c index f0cd08fa5c5d..5bc4e00a4a29 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -1440,9 +1440,9 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) } afe->regmap = syscon_node_to_regmap(dev->parent->of_node); - if (!afe->regmap) { + if (IS_ERR(afe->regmap)) { dev_err(dev, "could not get regmap from parent\n"); - return -ENODEV; + return PTR_ERR(afe->regmap); } mutex_init(&afe->irq_alloc_lock); -- cgit v1.2.3 From db51707b9c9aeedd310ebce60f15d5bb006567e0 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Fri, 5 Jan 2018 14:12:42 -0800 Subject: ASoC: rockchip: i2s: Support mono capture The Rockchip I2S controller only allows to configure even numbers of capture channels. It is still possible to capture monophonic audio by using dual-channel mode and ignoring the 'data' from the second channel. Signed-off-by: Matthias Kaehlcke Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 908211e1d6fc..cc22ab3d10dd 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -328,6 +328,7 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, val |= I2S_CHN_4; break; case 2: + case 1: val |= I2S_CHN_2; break; default: @@ -460,7 +461,7 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = { }, .capture = { .stream_name = "Capture", - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = (SNDRV_PCM_FMTBIT_S8 | @@ -654,7 +655,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev) } if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) { - if (val >= 2 && val <= 8) + if (val >= 1 && val <= 8) soc_dai->capture.channels_max = val; } -- cgit v1.2.3 From 5c256045b87b8aa8e5bc9d2e2fdc0802351c1f99 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 5 Jan 2018 14:55:33 -0600 Subject: ASoC: acpi: fix machine driver selection based on quirk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ACPI/machine-driver code refactoring introduced in 4.13 introduced a regression for cases where we need a DMI-based quirk to select the machine driver (the BIOS reports an invalid HID). The fix is just to make sure the results of the quirk are actually used. Fixes: 54746dabf770 ('ASoC: Improve machine driver selection based on quirk data') Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=96691 Tested-by: Nicole Færber Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/soc-acpi.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c index f21df28bc28e..d4dd2efea45e 100644 --- a/sound/soc/soc-acpi.c +++ b/sound/soc/soc-acpi.c @@ -84,11 +84,9 @@ snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines) for (mach = machines; mach->id[0]; mach++) { if (snd_soc_acpi_check_hid(mach->id) == true) { - if (mach->machine_quirk == NULL) - return mach; - - if (mach->machine_quirk(mach) != NULL) - return mach; + if (mach->machine_quirk) + mach = mach->machine_quirk(mach); + return mach; } } return NULL; -- cgit v1.2.3 From 0d5ea120abc020fada1f7cb019ec37f13162e7af Mon Sep 17 00:00:00 2001 From: Jeremy Cline Date: Fri, 5 Jan 2018 14:55:34 -0600 Subject: ASoC: Replace snd_soc_acpi_check_hid with acpi_dev_present Replace snd_soc_acpi_check_hid() with the generic acpi_dev_present() and remove the now unused snd_soc_acpi_check_hid function. This should have no functional change. Signed-off-by: Jeremy Cline Signed-off-by: Pierre-Louis Bossart Reviewed-by: Andy Shevchenko Signed-off-by: Mark Brown --- include/sound/soc-acpi.h | 3 --- sound/soc/soc-acpi.c | 32 ++------------------------------ 2 files changed, 2 insertions(+), 33 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index a7d8d335b043..057805489af3 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -49,9 +49,6 @@ snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], struct snd_soc_acpi_mach * snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines); -/* acpi check hid */ -bool snd_soc_acpi_check_hid(const u8 hid[ACPI_ID_LEN]); - /** * snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are * related to the hardware, except for the firmware and topology file names. diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c index d4dd2efea45e..7f43c9bf3d09 100644 --- a/sound/soc/soc-acpi.c +++ b/sound/soc/soc-acpi.c @@ -49,41 +49,13 @@ const char *snd_soc_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]) } EXPORT_SYMBOL_GPL(snd_soc_acpi_find_name_from_hid); -static acpi_status snd_soc_acpi_mach_match(acpi_handle handle, u32 level, - void *context, void **ret) -{ - unsigned long long sta; - acpi_status status; - - *(bool *)context = true; - status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); - if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) - *(bool *)context = false; - - return AE_OK; -} - -bool snd_soc_acpi_check_hid(const u8 hid[ACPI_ID_LEN]) -{ - acpi_status status; - bool found = false; - - status = acpi_get_devices(hid, snd_soc_acpi_mach_match, &found, NULL); - - if (ACPI_FAILURE(status)) - return false; - - return found; -} -EXPORT_SYMBOL_GPL(snd_soc_acpi_check_hid); - struct snd_soc_acpi_mach * snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines) { struct snd_soc_acpi_mach *mach; for (mach = machines; mach->id[0]; mach++) { - if (snd_soc_acpi_check_hid(mach->id) == true) { + if (acpi_dev_present(mach->id, NULL, -1)) { if (mach->machine_quirk) mach = mach->machine_quirk(mach); return mach; @@ -161,7 +133,7 @@ struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) return mach; for (i = 0; i < codec_list->num_codecs; i++) { - if (snd_soc_acpi_check_hid(codec_list->codecs[i]) != true) + if (!acpi_dev_present(codec_list->codecs[i], NULL, -1)) return NULL; } -- cgit v1.2.3 From 845ab40092601630ec9eb58398a53b9a87b6900b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Jan 2018 16:35:52 -0600 Subject: ASoC: acpi: add missing includes for non-ACPI platforms 0-day reports compilation issues with non-ACPI platforms. In file included from sound/soc/soc-acpi.c:17:0: >> include/sound/soc-acpi.h:36:46: error: 'ACPI_ID_LEN' undeclared here (not in a function); did you mean 'ACPI_FILE'? snd_soc_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]) sound/soc/soc-acpi.c: At top level: >> sound/soc/soc-acpi.c:174:16: error: expected declaration specifiers or '...' before string constant MODULE_LICENSE("GPL v2"); Add missing include files. Fixes: 7feb2f786a46 ("ASoC: move ACPI common code out of Intel/sst tree") Signed-off-by: Pierre-Louis Bossart Reviewed-by: Andy Shevchenko Acked-By: Vinod Koul Signed-off-by: Mark Brown --- include/sound/soc-acpi-intel-match.h | 1 + include/sound/soc-acpi.h | 1 + 2 files changed, 2 insertions(+) diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index 1a9191cd4bb3..9da6388c20a1 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -16,6 +16,7 @@ #ifndef __LINUX_SND_SOC_ACPI_INTEL_MATCH_H #define __LINUX_SND_SOC_ACPI_INTEL_MATCH_H +#include #include #include diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index a7d8d335b043..a93436089bf5 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -17,6 +17,7 @@ #include #include +#include struct snd_soc_acpi_package_context { char *name; /* package name */ -- cgit v1.2.3 From eaadb1caa966a91128297b754e90b7c92b350a00 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 6 Jan 2018 21:18:24 +0100 Subject: ASoC: Intel: sst: Fix the return value of 'sst_send_byte_stream_mrfld()' In some error handling paths, an error code is assiegned to 'ret'. However, the function always return 0. Fix it and return the error code if such an error paths is taken. Fixes: 3d9ff34622ba ("ASoC: Intel: sst: add stream operations") Signed-off-by: Christophe JAILLET Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index 65e257b17a7e..20f5066fefb9 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -220,7 +220,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, sst_free_block(sst_drv_ctx, block); out: test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id); - return 0; + return ret; } /* -- cgit v1.2.3 From 25f3fd043ec1f60f3955f9d7277d97e2f9c1612c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 6 Jan 2018 21:18:55 +0100 Subject: ASoC: Intel: sst: Fix some style This patch fixes 3 small issues: - missing 2nd '*' at the beginning of a doxygen comment - extra space after a '\n' in a dev_dbg message - extra tab before a 'return" statement Signed-off-by: Christophe JAILLET Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_stream.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index 20f5066fefb9..7ee6aeb7e0af 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -223,7 +223,7 @@ out: return ret; } -/* +/** * sst_pause_stream - Send msg for a pausing stream * @str_id: stream ID * @@ -261,7 +261,7 @@ int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) } } else { retval = -EBADRQC; - dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n "); + dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n"); } return retval; @@ -284,7 +284,7 @@ int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) if (!str_info) return -EINVAL; if (str_info->status == STREAM_RUNNING) - return 0; + return 0; if (str_info->status == STREAM_PAUSED) { retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD, -- cgit v1.2.3 From 56e49aa41da204f8582816c3f2572862c71adc90 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 5 Jan 2018 13:20:21 -0600 Subject: ASoC: Intel: bytcr_rt5651: fix Kiano DMI quirk The current code doesn't enable the MCLK which reduces audio quality (PLL driven from BLCK), fix the quirk Tested-by: Carlo Caione Signed-off-by: Pierre-Louis Bossart Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 488ec48f296a..de064f0f7b08 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -264,7 +264,8 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "KIANO"), DMI_MATCH(DMI_PRODUCT_NAME, "KIANO SlimNote 14.2"), }, - .driver_data = (void *)(BYT_RT5651_IN1_IN2_MAP), + .driver_data = (void *)(BYT_RT5651_MCLK_EN | + BYT_RT5651_IN1_IN2_MAP), }, {} }; -- cgit v1.2.3 From 60e3b52e9354550c28090237b083b20bbabed598 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 5 Jan 2018 13:20:18 -0600 Subject: ASoC: Intel: bytcr-rt5651: add quirk for IN3P which may also be used On Minnowboard Max with Realtek rt5651 eval board, the IN3P is connected to Headset Mic. Here add and select it for Minnowboard Max. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index de064f0f7b08..a958ed37569f 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -39,6 +39,7 @@ enum { BYT_RT5651_IN1_MAP, BYT_RT5651_IN2_MAP, BYT_RT5651_IN1_IN2_MAP, + BYT_RT5651_IN3_MAP, }; #define BYT_RT5651_MAP(quirk) ((quirk) & GENMASK(7, 0)) @@ -63,6 +64,8 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk IN1_MAP enabled"); if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN2_MAP) dev_info(dev, "quirk IN2_MAP enabled"); + if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN3_MAP) + dev_info(dev, "quirk IN3_MAP enabled"); if (byt_rt5651_quirk & BYT_RT5651_DMIC_EN) dev_info(dev, "quirk DMIC enabled"); if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) @@ -179,6 +182,12 @@ static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_in2_map[] = { {"IN3P", NULL, "Headset Mic"}, }; +static const struct snd_soc_dapm_route byt_rt5651_intmic_in3_map[] = { + {"Internal Mic", NULL, "micbias1"}, + {"IN3P", NULL, "Headset Mic"}, + {"IN1P", NULL, "Internal Mic"}, +}; + static const struct snd_kcontrol_new byt_rt5651_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), @@ -255,8 +264,7 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), }, - .driver_data = (void *)(BYT_RT5651_DMIC_MAP | - BYT_RT5651_DMIC_EN), + .driver_data = (void *)(BYT_RT5651_IN3_MAP), }, { .callback = byt_rt5651_quirk_cb, @@ -294,6 +302,10 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) custom_map = byt_rt5651_intmic_in1_in2_map; num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_in2_map); break; + case BYT_RT5651_IN3_MAP: + custom_map = byt_rt5651_intmic_in3_map; + num_routes = ARRAY_SIZE(byt_rt5651_intmic_in3_map); + break; default: custom_map = byt_rt5651_intmic_dmic_map; num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic_map); -- cgit v1.2.3 From 416f2b51119b8cdd899b226e4cf683d000797a8b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 5 Jan 2018 13:20:20 -0600 Subject: ASoC: Intel: bytcr-rt5651: enable MinnowBoard Turbot quirks Define DMI quirk for rt5651 eval board connected to MinnowBoard Turbot. The only difference with a MinnowBoard MAX is that the MCLK pin is enabled on the LSE connector Signed-off-by: Pierre-Louis Bossart Tested-by: Keqiao.Zhang Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index a958ed37569f..dfe6435f8ed0 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -266,6 +266,15 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = { }, .driver_data = (void *)(BYT_RT5651_IN3_MAP), }, + { + .callback = byt_rt5651_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ADI"), + DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Turbot"), + }, + .driver_data = (void *)(BYT_RT5651_MCLK_EN | + BYT_RT5651_IN3_MAP), + }, { .callback = byt_rt5651_quirk_cb, .matches = { -- cgit v1.2.3 From ea39bdcf22b084c6e6db0078f3140f0655a1e572 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 5 Jan 2018 13:20:23 -0600 Subject: ASoC: Intel: bytcr-rt5651: add support for Line In Add the DAPM widgets and routes. Tested with MinnowMax Turbot + rt5651 eval board with Speaker (LineOut) -> LineIn loopback Thanks to Bard Liao @ Realtek for providing the 0dB settings "IN Capture Volume" = 23 "ADC Capture Volume" = 47 "OUT Playback Volume" = 31 "DAC1 Playback Volume" = 175 Signed-off-by: Pierre-Louis Bossart Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index dfe6435f8ed0..22c9cc5d135e 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -131,6 +131,7 @@ static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Internal Mic", NULL), SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -142,6 +143,7 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = { {"Headset Mic", NULL, "Platform Clock"}, {"Internal Mic", NULL, "Platform Clock"}, {"Speaker", NULL, "Platform Clock"}, + {"Line In", NULL, "Platform Clock"}, {"AIF1 Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, @@ -155,6 +157,9 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = { {"Headphone", NULL, "HPOR"}, {"Speaker", NULL, "LOUTL"}, {"Speaker", NULL, "LOUTR"}, + {"IN2P", NULL, "Line In"}, + {"IN2N", NULL, "Line In"}, + }; static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic_map[] = { @@ -193,6 +198,7 @@ static const struct snd_kcontrol_new byt_rt5651_controls[] = { SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Internal Mic"), SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Line In"), }; static struct snd_soc_jack_pin bytcr_jack_pins[] = { -- cgit v1.2.3 From c66234cfedfc3e6e3b62563a5f2c1562be09a35d Mon Sep 17 00:00:00 2001 From: John Keeping Date: Mon, 8 Jan 2018 16:01:04 +0000 Subject: ASoC: rockchip: i2s: fix playback after runtime resume When restoring registers during runtime resume, we must not write to I2S_TXDR which is the transmit FIFO as this queues up a sample to be output and pushes all of the output channels down by one. This can be demonstrated with the speaker-test utility: for i in a b c; do speaker-test -c 2 -s 1; done which should play a test through the left speaker three times but if the I2S hardware starts runtime suspended the first sample will be played through the right speaker. Fix this by marking I2S_TXDR as volatile (which also requires marking it as readble, even though it technically isn't). This seems to be the most robust fix, the alternative of giving I2S_TXDR a default value is more fragile since it does not prevent regcache writing to the register in all circumstances. While here, also fix the configuration of I2S_RXDR and I2S_FIFOLR; these are not writable so they do not suffer from the same problem as I2S_TXDR but reading from I2S_RXDR does suffer from a similar problem. Fixes: f0447f6cbb20 ("ASoC: rockchip: i2s: restore register during runtime_suspend/resume cycle", 2016-09-07) Signed-off-by: John Keeping Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/rockchip/rockchip_i2s.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 908211e1d6fc..eb27f6c24bf7 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -504,6 +504,7 @@ static bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg) case I2S_INTCR: case I2S_XFER: case I2S_CLR: + case I2S_TXDR: case I2S_RXDR: case I2S_FIFOLR: case I2S_INTSR: @@ -518,6 +519,9 @@ static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg) switch (reg) { case I2S_INTSR: case I2S_CLR: + case I2S_FIFOLR: + case I2S_TXDR: + case I2S_RXDR: return true; default: return false; @@ -527,6 +531,8 @@ static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg) static bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg) { switch (reg) { + case I2S_RXDR: + return true; default: return false; } -- cgit v1.2.3 From c6059879be298cccda52f77bf019a7a99eb13e78 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Jan 2018 16:35:53 -0600 Subject: ASoC: Intel: Fix Kconfig with top-level selector Follow network example suggested by Linus, move Intel definitions in if/endif block and clarify in help text which options distro configurations should enable - everything except legacy Baytrail stuff and NOCODEC (test only) To avoid user confusion, machine drivers are handled with a submenu made dependent on this top-level selector. There should be no functionality change - except that sound capabilities are restored when using older configs without any user selection. Note that the SND_SOC_ACPI_INTEL_MATCH config is currently filtered out by the top-level selector. This will change in the near future to allow for this option to be selected by both SST and SOF drivers (simplification with submenu for machine drivers by Vinod Koul) Fixes: f6a118a800e3 ("ASoC: Intel: clarify Kconfig dependencies") Reported-by: Linus Torvalds Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul Reviewed-by: Andy Shevchenko Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 66 +++++++++++++++++++---------- sound/soc/intel/Makefile | 2 +- sound/soc/intel/boards/Kconfig | 94 +++++++++++++++++++++++------------------- 3 files changed, 97 insertions(+), 65 deletions(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 7b49d04e3c60..b827d3b70095 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -1,3 +1,19 @@ +config SND_SOC_INTEL_SST_TOPLEVEL + bool "Intel ASoC SST drivers" + default y + depends on X86 || COMPILE_TEST + select SND_SOC_INTEL_MACH + help + Intel ASoC SST Platform Drivers. If you have a Intel machine that + has an audio controller with a DSP and I2S or DMIC port, then + enable this option by saying Y + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Intel SST drivers. + +if SND_SOC_INTEL_SST_TOPLEVEL + config SND_SST_IPC tristate @@ -11,9 +27,6 @@ config SND_SST_IPC_ACPI select SND_SOC_INTEL_SST select IOSF_MBI -config SND_SOC_INTEL_COMMON - tristate - config SND_SOC_INTEL_SST tristate select SND_SOC_INTEL_SST_ACPI if ACPI @@ -25,47 +38,56 @@ config SND_SOC_INTEL_SST_FIRMWARE config SND_SOC_INTEL_SST_ACPI tristate -config SND_SOC_ACPI_INTEL_MATCH - tristate - select SND_SOC_ACPI if ACPI - -config SND_SOC_INTEL_SST_TOPLEVEL - tristate "Intel ASoC SST drivers" - depends on X86 || COMPILE_TEST - select SND_SOC_INTEL_MACH - select SND_SOC_INTEL_COMMON - help - Intel ASoC Audio Drivers. If you have a Intel machine that - has audio controller with a DSP and I2S or DMIC port, then - enable this option by saying Y or M - If unsure select "N". - config SND_SOC_INTEL_HASWELL tristate "Intel ASoC SST driver for Haswell/Broadwell" - depends on SND_SOC_INTEL_SST_TOPLEVEL && SND_DMA_SGBUF + depends on SND_DMA_SGBUF depends on DMADEVICES select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST_FIRMWARE + select SND_SOC_ACPI_INTEL_MATCH + help + If you have a Intel Haswell or Broadwell platform connected to + an I2S codec, then enable this option by saying Y or m. This is + typically used for Chromebooks. This is a recommended option. config SND_SOC_INTEL_BAYTRAIL tristate "Intel ASoC SST driver for Baytrail (legacy)" - depends on SND_SOC_INTEL_SST_TOPLEVEL depends on DMADEVICES select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST_FIRMWARE + select SND_SOC_ACPI_INTEL_MATCH + help + If you have a Intel Baytrail platform connected to an I2S codec, + then enable this option by saying Y or m. This was typically used + for Baytrail Chromebooks but this option is now deprecated and is + not recommended, use SND_SST_ATOM_HIFI2_PLATFORM instead. config SND_SST_ATOM_HIFI2_PLATFORM tristate "Intel ASoC SST driver for HiFi2 platforms (*field, *trail)" - depends on SND_SOC_INTEL_SST_TOPLEVEL && X86 + depends on X86 select SND_SOC_COMPRESS + select SND_SOC_ACPI_INTEL_MATCH config SND_SOC_INTEL_SKYLAKE tristate "Intel ASoC SST driver for SKL/BXT/KBL/GLK/CNL" - depends on SND_SOC_INTEL_SST_TOPLEVEL && PCI && ACPI + depends on PCI && ACPI select SND_HDA_EXT_CORE select SND_HDA_DSP_LOADER select SND_SOC_TOPOLOGY select SND_SOC_INTEL_SST + select SND_SOC_ACPI_INTEL_MATCH + help + If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ + GeminiLake or CannonLake platform with the DSP enabled in the BIOS + then enable this option by saying Y or m. + +config SND_SOC_ACPI_INTEL_MATCH + tristate + select SND_SOC_ACPI if ACPI + # this option controls the compilation of ACPI matching tables and + # helpers and is not meant to be selected by the user. + +endif ## SND_SOC_INTEL_SST_TOPLEVEL # ASoC codec drivers source "sound/soc/intel/boards/Kconfig" diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index b973d457e834..8160520fd74c 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # Core support -obj-$(CONFIG_SND_SOC_INTEL_COMMON) += common/ +obj-$(CONFIG_SND_SOC) += common/ # Platform Support obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/ diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 6f754708a48c..08481882c240 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -1,7 +1,14 @@ -config SND_SOC_INTEL_MACH - tristate "Intel Audio machine drivers" +menuconfig SND_SOC_INTEL_MACH + bool "Intel Machine drivers" depends on SND_SOC_INTEL_SST_TOPLEVEL - select SND_SOC_ACPI_INTEL_MATCH if ACPI + help + Intel ASoC Machine Drivers. If you have a Intel machine that + has an audio controller with a DSP and I2S or DMIC port, then + enable this option by saying Y + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Intel ASoC machine drivers. if SND_SOC_INTEL_MACH @@ -17,103 +24,106 @@ config SND_MFLD_MACHINE Say Y if you have such a device. If unsure select "N". +if SND_SOC_INTEL_HASWELL + config SND_SOC_INTEL_HASWELL_MACH tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM - depends on SND_SOC_INTEL_HASWELL select SND_SOC_RT5640 help This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell - Ultrabook platforms. - Say Y if you have such a device. + Ultrabook platforms. This is a recommended option. + Say Y or m if you have such a device. If unsure select "N". config SND_SOC_INTEL_BDW_RT5677_MACH tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec" depends on X86_INTEL_LPSS && GPIOLIB && I2C - depends on SND_SOC_INTEL_HASWELL select SND_SOC_RT5677 help This adds support for Intel Broadwell platform based boards with - the RT5677 audio codec. + the RT5677 audio codec. This is a recommended option. + Say Y or m if you have such a device. + If unsure select "N". config SND_SOC_INTEL_BROADWELL_MACH tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM - depends on SND_SOC_INTEL_HASWELL select SND_SOC_RT286 help This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell Ultrabook platforms. - Say Y if you have such a device. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +endif + +if SND_SOC_INTEL_BAYTRAIL config SND_SOC_INTEL_BYT_MAX98090_MACH tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" depends on X86_INTEL_LPSS && I2C - depends on SND_SST_IPC_ACPI = n - depends on SND_SOC_INTEL_BAYTRAIL select SND_SOC_MAX98090 help This adds audio driver for Intel Baytrail platform based boards - with the MAX98090 audio codec. + with the MAX98090 audio codec. This driver is deprecated, use + SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH instead for better + functionality. config SND_SOC_INTEL_BYT_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" depends on X86_INTEL_LPSS && I2C - depends on SND_SST_IPC_ACPI = n - depends on SND_SOC_INTEL_BAYTRAIL select SND_SOC_RT5640 help This adds audio driver for Intel Baytrail platform based boards with the RT5640 audio codec. This driver is deprecated, use SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality. +endif + +if SND_SST_ATOM_HIFI2_PLATFORM + config SND_SOC_INTEL_BYTCR_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec" depends on X86 && I2C && ACPI select SND_SOC_RT5640 - depends on SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR platforms with RT5640 audio codec. - Say Y if you have such a device. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_BYTCR_RT5651_MACH tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec" depends on X86 && I2C && ACPI select SND_SOC_RT5651 - depends on SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR platforms with RT5651 audio codec. - Say Y if you have such a device. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_CHT_BSW_RT5672_MACH tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_RT5670 - depends on SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with RT5672 audio codec. - Say Y if you have such a device. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_CHT_BSW_RT5645_MACH tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_RT5645 - depends on SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with RT5645/5650 audio codec. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH @@ -121,63 +131,67 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_MAX98090 select SND_SOC_TS3A227E - depends on SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with MAX98090 audio codec it also can support TI jack chip as aux device. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_BYT_CHT_DA7213_MACH tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with DA7212/7213 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_DA7213 - depends on SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for Intel(R) Baytrail & CherryTrail platforms with DA7212/7213 audio codec. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_BYT_CHT_ES8316_MACH tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with ES8316 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_ES8316 - depends on SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for Intel(R) Baytrail & Cherrytrail platforms with ES8316 audio codec. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)" depends on X86_INTEL_LPSS && I2C && ACPI - depends on SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for the MinnowBoard Max or Up boards and provides access to I2S signals on the Low-Speed - connector + connector. This is not a recommended option outside of these cases. + It is not intended to be enabled by distros by default. + Say Y or m if you have such a device. + If unsure select "N". +endif + +if SND_SOC_INTEL_SKYLAKE + config SND_SOC_INTEL_SKL_RT286_MACH tristate "ASoC Audio driver for SKL with RT286 I2S mode" depends on X86 && ACPI && I2C - depends on SND_SOC_INTEL_SKYLAKE select SND_SOC_RT286 select SND_SOC_DMIC select SND_SOC_HDAC_HDMI help This adds support for ASoC machine driver for Skylake platforms with RT286 I2S audio codec. - Say Y if you have such a device. + Say Y or m if you have such a device. If unsure select "N". config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode" depends on X86_INTEL_LPSS && I2C - depends on SND_SOC_INTEL_SKYLAKE select SND_SOC_NAU8825 select SND_SOC_SSM4567 select SND_SOC_DMIC @@ -185,13 +199,12 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH help This adds support for ASoC Onboard Codec I2S machine driver. This will create an alsa sound card for NAU88L25 + SSM4567. - Say Y if you have such a device. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode" depends on X86_INTEL_LPSS && I2C - depends on SND_SOC_INTEL_SKYLAKE select SND_SOC_NAU8825 select SND_SOC_MAX98357A select SND_SOC_DMIC @@ -199,13 +212,12 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH help This adds support for ASoC Onboard Codec I2S machine driver. This will create an alsa sound card for NAU88L25 + MAX98357A. - Say Y if you have such a device. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode" depends on X86 && ACPI && I2C - depends on SND_SOC_INTEL_SKYLAKE select SND_SOC_DA7219 select SND_SOC_MAX98357A select SND_SOC_DMIC @@ -214,13 +226,12 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH help This adds support for ASoC machine driver for Broxton-P platforms with DA7219 + MAX98357A I2S audio codec. - Say Y if you have such a device. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_BXT_RT298_MACH tristate "ASoC Audio driver for Broxton with RT298 I2S mode" depends on X86 && ACPI && I2C - depends on SND_SOC_INTEL_SKYLAKE select SND_SOC_RT298 select SND_SOC_DMIC select SND_SOC_HDAC_HDMI @@ -228,14 +239,13 @@ config SND_SOC_INTEL_BXT_RT298_MACH help This adds support for ASoC machine driver for Broxton platforms with RT286 I2S audio codec. - Say Y if you have such a device. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH tristate "ASoC Audio driver for KBL with RT5663 and MAX98927 in I2S Mode" depends on X86_INTEL_LPSS && I2C select SND_SOC_INTEL_SST - depends on SND_SOC_INTEL_SKYLAKE select SND_SOC_RT5663 select SND_SOC_MAX98927 select SND_SOC_DMIC @@ -243,14 +253,13 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH help This adds support for ASoC Onboard Codec I2S machine driver. This will create an alsa sound card for RT5663 + MAX98927. - Say Y if you have such a device. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode" depends on X86_INTEL_LPSS && I2C && SPI select SND_SOC_INTEL_SST - depends on SND_SOC_INTEL_SKYLAKE select SND_SOC_RT5663 select SND_SOC_RT5514 select SND_SOC_RT5514_SPI @@ -259,7 +268,8 @@ config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH help This adds support for ASoC Onboard Codec I2S machine driver. This will create an alsa sound card for RT5663 + RT5514 + MAX98927. - Say Y if you have such a device. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". - endif + +endif ## SND_SOC_INTEL_MACH -- cgit v1.2.3 From 4772c16ede522d46219a59646503d2020841a6f4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Jan 2018 16:35:54 -0600 Subject: ASoC: Intel: Kconfig: Simplify-clarify ACPI/PCI dependencies PCI/ACPI selections should not happen in Kconfig for machine drivers, move to SOC selections. Add distinction between PCI and ACPI HiFi2 platforms and help text. There should be no functionality change. The PCI-based platforms may be removed at some point since Medfield is not really supported by anyone, and with Edison now defunct support for Merrifield/Edison is to be determined. The dependency on SND_DMA_SGBUF for Haswell is not clear at this point and may have to be further updated. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Andy Shevchenko Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 27 +++++++++++++++++++++++---- sound/soc/intel/boards/Kconfig | 14 ++++---------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index b827d3b70095..16374576cb6e 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -41,7 +41,7 @@ config SND_SOC_INTEL_SST_ACPI config SND_SOC_INTEL_HASWELL tristate "Intel ASoC SST driver for Haswell/Broadwell" depends on SND_DMA_SGBUF - depends on DMADEVICES + depends on DMADEVICES && ACPI select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST_FIRMWARE select SND_SOC_ACPI_INTEL_MATCH @@ -52,7 +52,7 @@ config SND_SOC_INTEL_HASWELL config SND_SOC_INTEL_BAYTRAIL tristate "Intel ASoC SST driver for Baytrail (legacy)" - depends on DMADEVICES + depends on DMADEVICES && ACPI select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST_FIRMWARE select SND_SOC_ACPI_INTEL_MATCH @@ -62,11 +62,30 @@ config SND_SOC_INTEL_BAYTRAIL for Baytrail Chromebooks but this option is now deprecated and is not recommended, use SND_SST_ATOM_HIFI2_PLATFORM instead. +config SND_SST_ATOM_HIFI2_PLATFORM_PCI + tristate "Intel ASoC SST driver for PCI HiFi2 platforms (Medfield, Merrifield)" + depends on X86 && PCI + select SND_SST_IPC_PCI + select SND_SOC_COMPRESS + select SND_SOC_INTEL_COMMON + help + If you have a Intel Medfield or Merrifield/Edison platform, then + enable this option by saying Y or m. Distros will typically not + enable this option: Medfield devices are not available to + developers and while Merrifield/Edison can run a mainline kernel with + limited functionality it will require a firmware file which + is not in the standard firmware tree + config SND_SST_ATOM_HIFI2_PLATFORM - tristate "Intel ASoC SST driver for HiFi2 platforms (*field, *trail)" - depends on X86 + tristate "Intel ASoC SST driver for ACPI HiFi2 platforms (Baytrail, Cherrytrail)" + depends on X86 && ACPI + select SND_SST_IPC_ACPI select SND_SOC_COMPRESS select SND_SOC_ACPI_INTEL_MATCH + help + If you have a Intel Baytrail or Cherrytrail platform with an I2S + codec, then enable this option by saying Y or m. This is a + recommended option config SND_SOC_INTEL_SKYLAKE tristate "Intel ASoC SST driver for SKL/BXT/KBL/GLK/CNL" diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 08481882c240..e926f9747232 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -12,18 +12,20 @@ menuconfig SND_SOC_INTEL_MACH if SND_SOC_INTEL_MACH +if SND_SST_ATOM_HIFI2_PLATFORM_PCI + config SND_MFLD_MACHINE tristate "SOC Machine Audio driver for Intel Medfield MID platform" depends on INTEL_SCU_IPC select SND_SOC_SN95031 - depends on SND_SST_ATOM_HIFI2_PLATFORM - select SND_SST_IPC_PCI help This adds support for ASoC machine driver for Intel(R) MID Medfield platform used as alsa device in audio substem in Intel(R) MID devices Say Y if you have such a device. If unsure select "N". +endif + if SND_SOC_INTEL_HASWELL config SND_SOC_INTEL_HASWELL_MACH @@ -86,7 +88,6 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec" depends on X86 && I2C && ACPI select SND_SOC_RT5640 - select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR platforms with RT5640 audio codec. @@ -97,7 +98,6 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec" depends on X86 && I2C && ACPI select SND_SOC_RT5651 - select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR platforms with RT5651 audio codec. @@ -108,7 +108,6 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_RT5670 - select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with RT5672 audio codec. @@ -119,7 +118,6 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_RT5645 - select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with RT5645/5650 audio codec. @@ -131,7 +129,6 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_MAX98090 select SND_SOC_TS3A227E - select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with MAX98090 audio codec it also can support TI jack chip as aux device. @@ -142,7 +139,6 @@ config SND_SOC_INTEL_BYT_CHT_DA7213_MACH tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with DA7212/7213 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_DA7213 - select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for Intel(R) Baytrail & CherryTrail platforms with DA7212/7213 audio codec. @@ -153,7 +149,6 @@ config SND_SOC_INTEL_BYT_CHT_ES8316_MACH tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with ES8316 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_ES8316 - select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for Intel(R) Baytrail & Cherrytrail platforms with ES8316 audio codec. @@ -163,7 +158,6 @@ config SND_SOC_INTEL_BYT_CHT_ES8316_MACH config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)" depends on X86_INTEL_LPSS && I2C && ACPI - select SND_SST_IPC_ACPI help This adds support for ASoC machine driver for the MinnowBoard Max or Up boards and provides access to I2S signals on the Low-Speed -- cgit v1.2.3 From def2c4284fd6b3402265ee050d769897e3331521 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Jan 2018 16:35:55 -0600 Subject: ASoC: Intel: document what Kconfig options do Document in comments what the options are supposed to mean, before clean-up in next patch. No functionality change here. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Andy Shevchenko Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 16374576cb6e..01b75df6b118 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -16,16 +16,27 @@ if SND_SOC_INTEL_SST_TOPLEVEL config SND_SST_IPC tristate + # This option controls the IPC core for HiFi2 platforms config SND_SST_IPC_PCI tristate select SND_SST_IPC + # This option controls the PCI-based IPC for HiFi2 platforms + # (Medfield, Merrifield). config SND_SST_IPC_ACPI tristate select SND_SST_IPC select SND_SOC_INTEL_SST select IOSF_MBI + # This option controls the ACPI-based IPC for HiFi2 platforms + # (Baytrail, Cherrytrail) + +config SND_SOC_INTEL_SST_ACPI + tristate + # This option controls ACPI-based probing on + # Haswell/Broadwell/Baytrail legacy and will be set + # when these platforms are enabled config SND_SOC_INTEL_SST tristate @@ -34,9 +45,9 @@ config SND_SOC_INTEL_SST config SND_SOC_INTEL_SST_FIRMWARE tristate select DW_DMAC_CORE - -config SND_SOC_INTEL_SST_ACPI - tristate + # This option controls firmware download on + # Haswell/Broadwell/Baytrail legacy and will be set + # when these platforms are enabled config SND_SOC_INTEL_HASWELL tristate "Intel ASoC SST driver for Haswell/Broadwell" -- cgit v1.2.3 From f3f2bb7a0ebf9d83229810f69a53fee2c0441b2c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Jan 2018 16:35:56 -0600 Subject: ASoC: Intel: Fix nested/unnecessary Kconfig dependencies This patch fixes a number of issues: 1. IOSF_MBI is only needed for byt-cr detection, which is only supported on Baytrail/Cherrytrail, move to HiFi2 config 2. SND_SOC_INTEL_SST should not select SND_SOC_INTEL_SST_ACPI, the latter config is only valid for Haswell/Baytrail legacy but not needed by Skylake 3. SND_SST_IPC_ACPI, used only by the atom/sst driver, should not select SND_SOC_INTEL_SST, none of the code under common/sst*.c is used This nesting of configs really makes no sense, it's easier to maintain if for each platform one can control what is strictly required. Compiled-tested with each of Haswell, Baytrail legacy, HiFi2, SKL cases selected independently. 0-day and explicit randconfig tests did not report additional issues and no functionality loss was observed in Intel tests on HIFI2 and SKYLAKE platforms Signed-off-by: Pierre-Louis Bossart Reviewed-by: Andy Shevchenko Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 01b75df6b118..ca0d6eb95d11 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -27,8 +27,6 @@ config SND_SST_IPC_PCI config SND_SST_IPC_ACPI tristate select SND_SST_IPC - select SND_SOC_INTEL_SST - select IOSF_MBI # This option controls the ACPI-based IPC for HiFi2 platforms # (Baytrail, Cherrytrail) @@ -40,7 +38,6 @@ config SND_SOC_INTEL_SST_ACPI config SND_SOC_INTEL_SST tristate - select SND_SOC_INTEL_SST_ACPI if ACPI config SND_SOC_INTEL_SST_FIRMWARE tristate @@ -54,6 +51,7 @@ config SND_SOC_INTEL_HASWELL depends on SND_DMA_SGBUF depends on DMADEVICES && ACPI select SND_SOC_INTEL_SST + select SND_SOC_INTEL_SST_ACPI select SND_SOC_INTEL_SST_FIRMWARE select SND_SOC_ACPI_INTEL_MATCH help @@ -65,6 +63,7 @@ config SND_SOC_INTEL_BAYTRAIL tristate "Intel ASoC SST driver for Baytrail (legacy)" depends on DMADEVICES && ACPI select SND_SOC_INTEL_SST + select SND_SOC_INTEL_SST_ACPI select SND_SOC_INTEL_SST_FIRMWARE select SND_SOC_ACPI_INTEL_MATCH help @@ -93,6 +92,7 @@ config SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI select SND_SOC_COMPRESS select SND_SOC_ACPI_INTEL_MATCH + select IOSF_MBI help If you have a Intel Baytrail or Cherrytrail platform with an I2S codec, then enable this option by saying Y or m. This is a -- cgit v1.2.3 From 043f5a0b8d6e4b9cb373978ca1883fe16287abfd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Jan 2018 16:35:57 -0600 Subject: ASoC: Intel: boards: align Kconfig dependencies for Haswell/Broadwell Make sure that the same I2C/I2C_DESIGNWARE_PLATFORM are selected. The latter might actually need to be moved to the SOC side of things, it really has no place in a machine driver dependency Signed-off-by: Pierre-Louis Bossart Reviewed-by: Andy Shevchenko Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index e926f9747232..358f8f33adc4 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -40,7 +40,7 @@ config SND_SOC_INTEL_HASWELL_MACH config SND_SOC_INTEL_BDW_RT5677_MACH tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec" - depends on X86_INTEL_LPSS && GPIOLIB && I2C + depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM && GPIOLIB select SND_SOC_RT5677 help This adds support for Intel Broadwell platform based boards with -- cgit v1.2.3 From 99644597d71333866070f0223bffa62c03f36587 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Jan 2018 16:35:58 -0600 Subject: ASoC: Intel: boards: align Kconfig configurations for HiFi2 Make sure all the configs are aligned Also add the missing dependencies on SOC_ACPI stuff used to fix DAI names based on HID and fix a couple of indentation issues Signed-off-by: Pierre-Louis Bossart Reviewed-by: Andy Shevchenko Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 358f8f33adc4..08c482cc02f7 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -85,29 +85,32 @@ endif if SND_SST_ATOM_HIFI2_PLATFORM config SND_SOC_INTEL_BYTCR_RT5640_MACH - tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec" - depends on X86 && I2C && ACPI + tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec" + depends on X86_INTEL_LPSS && I2C && ACPI + select SND_SOC_ACPI select SND_SOC_RT5640 help - This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR - platforms with RT5640 audio codec. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". + This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR + platforms with RT5640 audio codec. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". config SND_SOC_INTEL_BYTCR_RT5651_MACH - tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec" - depends on X86 && I2C && ACPI + tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec" + depends on X86_INTEL_LPSS && I2C && ACPI + select SND_SOC_ACPI select SND_SOC_RT5651 help - This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR - platforms with RT5651 audio codec. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". + This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR + platforms with RT5651 audio codec. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". config SND_SOC_INTEL_CHT_BSW_RT5672_MACH - tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" + tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" depends on X86_INTEL_LPSS && I2C && ACPI - select SND_SOC_RT5670 + select SND_SOC_ACPI + select SND_SOC_RT5670 help This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with RT5672 audio codec. @@ -117,6 +120,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH config SND_SOC_INTEL_CHT_BSW_RT5645_MACH tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec" depends on X86_INTEL_LPSS && I2C && ACPI + select SND_SOC_ACPI select SND_SOC_RT5645 help This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell @@ -138,6 +142,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH config SND_SOC_INTEL_BYT_CHT_DA7213_MACH tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with DA7212/7213 codec" depends on X86_INTEL_LPSS && I2C && ACPI + select SND_SOC_ACPI select SND_SOC_DA7213 help This adds support for ASoC machine driver for Intel(R) Baytrail & CherryTrail -- cgit v1.2.3 From 969eaef7710400e39be13190bace40910555d426 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Jan 2018 16:35:59 -0600 Subject: ASoC: Intel: boards: align/fix SKL/BXT/KBL Kconfigs No reason why SND_SOC_INTEL_SST should be set here. Also make sure same dependencies are used everywhere (only last one has SPI in addition). Replace X86_INTEL_LPSS by MFD_INTEL_LPSS since the former makes no sense for Skylake+ devices Signed-off-by: Pierre-Louis Bossart Reviewed-by: Andy Shevchenko Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 08c482cc02f7..063611ad641c 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -178,7 +178,7 @@ if SND_SOC_INTEL_SKYLAKE config SND_SOC_INTEL_SKL_RT286_MACH tristate "ASoC Audio driver for SKL with RT286 I2S mode" - depends on X86 && ACPI && I2C + depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_RT286 select SND_SOC_DMIC select SND_SOC_HDAC_HDMI @@ -190,7 +190,7 @@ config SND_SOC_INTEL_SKL_RT286_MACH config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode" - depends on X86_INTEL_LPSS && I2C + depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_NAU8825 select SND_SOC_SSM4567 select SND_SOC_DMIC @@ -203,7 +203,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode" - depends on X86_INTEL_LPSS && I2C + depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_NAU8825 select SND_SOC_MAX98357A select SND_SOC_DMIC @@ -216,7 +216,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode" - depends on X86 && ACPI && I2C + depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_DA7219 select SND_SOC_MAX98357A select SND_SOC_DMIC @@ -230,7 +230,7 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH config SND_SOC_INTEL_BXT_RT298_MACH tristate "ASoC Audio driver for Broxton with RT298 I2S mode" - depends on X86 && ACPI && I2C + depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_RT298 select SND_SOC_DMIC select SND_SOC_HDAC_HDMI @@ -243,8 +243,7 @@ config SND_SOC_INTEL_BXT_RT298_MACH config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH tristate "ASoC Audio driver for KBL with RT5663 and MAX98927 in I2S Mode" - depends on X86_INTEL_LPSS && I2C - select SND_SOC_INTEL_SST + depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_RT5663 select SND_SOC_MAX98927 select SND_SOC_DMIC @@ -257,8 +256,8 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode" - depends on X86_INTEL_LPSS && I2C && SPI - select SND_SOC_INTEL_SST + depends on MFD_INTEL_LPSS && I2C && ACPI + depends on SPI select SND_SOC_RT5663 select SND_SOC_RT5514 select SND_SOC_RT5514_SPI -- cgit v1.2.3 From 89671061116f83bd8b8b01d1c9620a26b221725f Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 4 Jan 2018 16:36:00 -0600 Subject: ASoC: Intel: kconfig: add some comments for if symbols Help in finding matching "if" endings by commenting the "endif". Signed-off-by: Vinod Koul Signed-off-by: Pierre-Louis Bossart Reviewed-by: Andy Shevchenko Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 063611ad641c..e1b6addcd13d 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -24,7 +24,7 @@ config SND_MFLD_MACHINE Say Y if you have such a device. If unsure select "N". -endif +endif ## SND_SST_ATOM_HIFI2_PLATFORM_PCI if SND_SOC_INTEL_HASWELL @@ -57,7 +57,7 @@ config SND_SOC_INTEL_BROADWELL_MACH Ultrabook platforms. Say Y or m if you have such a device. This is a recommended option. If unsure select "N". -endif +endif ## SND_SOC_INTEL_HASWELL if SND_SOC_INTEL_BAYTRAIL @@ -80,7 +80,7 @@ config SND_SOC_INTEL_BYT_RT5640_MACH with the RT5640 audio codec. This driver is deprecated, use SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality. -endif +endif ## SND_SOC_INTEL_BAYTRAIL if SND_SST_ATOM_HIFI2_PLATFORM @@ -172,7 +172,7 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH If unsure select "N". -endif +endif ## SND_SST_ATOM_HIFI2_PLATFORM if SND_SOC_INTEL_SKYLAKE @@ -268,6 +268,6 @@ config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH create an alsa sound card for RT5663 + RT5514 + MAX98927. Say Y or m if you have such a device. This is a recommended option. If unsure select "N". -endif +endif ## SND_SOC_INTEL_SKYLAKE endif ## SND_SOC_INTEL_MACH -- cgit v1.2.3 From 8fca15839ce5c473c57356abe36e166367e6c6ef Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 4 Jan 2018 16:36:01 -0600 Subject: ASoC: Intel: kconfig: drop boiler plate text from config items Drop "Intel ASoC SST driver for " platforms and "SOC Machine Audio driver for Intel" for machines.. Signed-off-by: Vinod Koul Signed-off-by: Pierre-Louis Bossart Reviewed-by: Andy Shevchenko Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 10 +++++----- sound/soc/intel/boards/Kconfig | 42 +++++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index ca0d6eb95d11..b0bd1938b71e 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -47,7 +47,7 @@ config SND_SOC_INTEL_SST_FIRMWARE # when these platforms are enabled config SND_SOC_INTEL_HASWELL - tristate "Intel ASoC SST driver for Haswell/Broadwell" + tristate "Haswell/Broadwell Platforms" depends on SND_DMA_SGBUF depends on DMADEVICES && ACPI select SND_SOC_INTEL_SST @@ -60,7 +60,7 @@ config SND_SOC_INTEL_HASWELL typically used for Chromebooks. This is a recommended option. config SND_SOC_INTEL_BAYTRAIL - tristate "Intel ASoC SST driver for Baytrail (legacy)" + tristate "Baytrail (legacy) Platforms" depends on DMADEVICES && ACPI select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST_ACPI @@ -73,7 +73,7 @@ config SND_SOC_INTEL_BAYTRAIL not recommended, use SND_SST_ATOM_HIFI2_PLATFORM instead. config SND_SST_ATOM_HIFI2_PLATFORM_PCI - tristate "Intel ASoC SST driver for PCI HiFi2 platforms (Medfield, Merrifield)" + tristate "PCI HiFi2 (Medfield, Merrifield) Platforms" depends on X86 && PCI select SND_SST_IPC_PCI select SND_SOC_COMPRESS @@ -87,7 +87,7 @@ config SND_SST_ATOM_HIFI2_PLATFORM_PCI is not in the standard firmware tree config SND_SST_ATOM_HIFI2_PLATFORM - tristate "Intel ASoC SST driver for ACPI HiFi2 platforms (Baytrail, Cherrytrail)" + tristate "ACPI HiFi2 (Baytrail, Cherrytrail) Platforms" depends on X86 && ACPI select SND_SST_IPC_ACPI select SND_SOC_COMPRESS @@ -99,7 +99,7 @@ config SND_SST_ATOM_HIFI2_PLATFORM recommended option config SND_SOC_INTEL_SKYLAKE - tristate "Intel ASoC SST driver for SKL/BXT/KBL/GLK/CNL" + tristate "SKL/BXT/KBL/GLK/CNL... Platforms" depends on PCI && ACPI select SND_HDA_EXT_CORE select SND_HDA_DSP_LOADER diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index e1b6addcd13d..12761d8fd8a5 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -15,7 +15,7 @@ if SND_SOC_INTEL_MACH if SND_SST_ATOM_HIFI2_PLATFORM_PCI config SND_MFLD_MACHINE - tristate "SOC Machine Audio driver for Intel Medfield MID platform" + tristate "Medfield (Intel MID)" depends on INTEL_SCU_IPC select SND_SOC_SN95031 help @@ -29,7 +29,7 @@ endif ## SND_SST_ATOM_HIFI2_PLATFORM_PCI if SND_SOC_INTEL_HASWELL config SND_SOC_INTEL_HASWELL_MACH - tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" + tristate "Haswell Lynxpoint" depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM select SND_SOC_RT5640 help @@ -39,7 +39,7 @@ config SND_SOC_INTEL_HASWELL_MACH If unsure select "N". config SND_SOC_INTEL_BDW_RT5677_MACH - tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec" + tristate "Broadwell with RT5677 codec" depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM && GPIOLIB select SND_SOC_RT5677 help @@ -49,7 +49,7 @@ config SND_SOC_INTEL_BDW_RT5677_MACH If unsure select "N". config SND_SOC_INTEL_BROADWELL_MACH - tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" + tristate "Broadwell Wildcatpoint" depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM select SND_SOC_RT286 help @@ -62,7 +62,7 @@ endif ## SND_SOC_INTEL_HASWELL if SND_SOC_INTEL_BAYTRAIL config SND_SOC_INTEL_BYT_MAX98090_MACH - tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" + tristate "Baytrail with MAX98090 codec" depends on X86_INTEL_LPSS && I2C select SND_SOC_MAX98090 help @@ -72,7 +72,7 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH functionality. config SND_SOC_INTEL_BYT_RT5640_MACH - tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" + tristate "Baytrail with RT5640 codec" depends on X86_INTEL_LPSS && I2C select SND_SOC_RT5640 help @@ -85,7 +85,7 @@ endif ## SND_SOC_INTEL_BAYTRAIL if SND_SST_ATOM_HIFI2_PLATFORM config SND_SOC_INTEL_BYTCR_RT5640_MACH - tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec" + tristate "Baytrail and Baytrail-CR with RT5640 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_ACPI select SND_SOC_RT5640 @@ -96,7 +96,7 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH If unsure select "N". config SND_SOC_INTEL_BYTCR_RT5651_MACH - tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec" + tristate "Baytrail and Baytrail-CR with RT5651 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_ACPI select SND_SOC_RT5651 @@ -107,7 +107,7 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH If unsure select "N". config SND_SOC_INTEL_CHT_BSW_RT5672_MACH - tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" + tristate "Cherrytrail & Braswell with RT5672 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_ACPI select SND_SOC_RT5670 @@ -118,7 +118,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH If unsure select "N". config SND_SOC_INTEL_CHT_BSW_RT5645_MACH - tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec" + tristate "Cherrytrail & Braswell with RT5645/5650 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_ACPI select SND_SOC_RT5645 @@ -129,7 +129,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH If unsure select "N". config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH - tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 & TI codec" + tristate "Cherrytrail & Braswell with MAX98090 & TI codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_MAX98090 select SND_SOC_TS3A227E @@ -140,7 +140,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH If unsure select "N". config SND_SOC_INTEL_BYT_CHT_DA7213_MACH - tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with DA7212/7213 codec" + tristate "Baytrail & Cherrytrail with DA7212/7213 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_ACPI select SND_SOC_DA7213 @@ -151,7 +151,7 @@ config SND_SOC_INTEL_BYT_CHT_DA7213_MACH If unsure select "N". config SND_SOC_INTEL_BYT_CHT_ES8316_MACH - tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with ES8316 codec" + tristate "Baytrail & Cherrytrail with ES8316 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_ES8316 help @@ -161,7 +161,7 @@ config SND_SOC_INTEL_BYT_CHT_ES8316_MACH If unsure select "N". config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH - tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)" + tristate "Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)" depends on X86_INTEL_LPSS && I2C && ACPI help This adds support for ASoC machine driver for the MinnowBoard Max or @@ -177,7 +177,7 @@ endif ## SND_SST_ATOM_HIFI2_PLATFORM if SND_SOC_INTEL_SKYLAKE config SND_SOC_INTEL_SKL_RT286_MACH - tristate "ASoC Audio driver for SKL with RT286 I2S mode" + tristate "SKL with RT286 I2S mode" depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_RT286 select SND_SOC_DMIC @@ -189,7 +189,7 @@ config SND_SOC_INTEL_SKL_RT286_MACH If unsure select "N". config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH - tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode" + tristate "SKL with NAU88L25 and SSM4567 in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_NAU8825 select SND_SOC_SSM4567 @@ -202,7 +202,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH If unsure select "N". config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH - tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode" + tristate "SKL with NAU88L25 and MAX98357A in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_NAU8825 select SND_SOC_MAX98357A @@ -215,7 +215,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH If unsure select "N". config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH - tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode" + tristate "Broxton with DA7219 and MAX98357A in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_DA7219 select SND_SOC_MAX98357A @@ -229,7 +229,7 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH If unsure select "N". config SND_SOC_INTEL_BXT_RT298_MACH - tristate "ASoC Audio driver for Broxton with RT298 I2S mode" + tristate "Broxton with RT298 I2S mode" depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_RT298 select SND_SOC_DMIC @@ -242,7 +242,7 @@ config SND_SOC_INTEL_BXT_RT298_MACH If unsure select "N". config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH - tristate "ASoC Audio driver for KBL with RT5663 and MAX98927 in I2S Mode" + tristate "KBL with RT5663 and MAX98927 in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_RT5663 select SND_SOC_MAX98927 @@ -255,7 +255,7 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH If unsure select "N". config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH - tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode" + tristate "KBL with RT5663, RT5514 and MAX98927 in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI depends on SPI select SND_SOC_RT5663 -- cgit v1.2.3 From c64ed5dd9feba193c76eb460b451225ac2a0d87b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 9 Jan 2018 08:51:02 +0100 Subject: ALSA: pcm: Use ERESTARTSYS instead of EINTR in OSS emulation Fix the last standing EINTR in the whole subsystem. Use more correct ERESTARTSYS for pending signals. Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index c7d8489d39c8..e8b19876c420 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -842,7 +842,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, if (!(mutex_trylock(&runtime->oss.params_lock))) return -EAGAIN; } else if (mutex_lock_interruptible(&runtime->oss.params_lock)) - return -EINTR; + return -ERESTARTSYS; sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL); params = kmalloc(sizeof(*params), GFP_KERNEL); sparams = kmalloc(sizeof(*sparams), GFP_KERNEL); -- cgit v1.2.3 From 7fb59e940f6225beed0b24cd09e9fad9aebb7565 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Fri, 5 Jan 2018 12:39:57 -0800 Subject: ASoC: codecs: dmic: Make number of channels configurable The DMIC DAI driver specifies a number of 1 to 8 channels for each DAI. The actual number of mics can currently not be configured in the device tree or audio glue, but is derived from the min/max channels of the CPU and codec DAI. A typical CPU DAI has two or more channels, in consequence a single mic is treated as a stereo/multi channel device, even though only one channel carries audio data. This change adds the option to specify the number of used DMIC channels in the device tree. When specified this value overwrites the default channels_max value of 8 in the snd_soc_dai_driver struct of the codec. Signed-off-by: Matthias Kaehlcke Reviewed-by: Rob Herring Acked-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/dmic.txt | 2 ++ sound/soc/codecs/dmic.c | 24 +++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/dmic.txt b/Documentation/devicetree/bindings/sound/dmic.txt index 54c8ef6498a8..f7bf65611453 100644 --- a/Documentation/devicetree/bindings/sound/dmic.txt +++ b/Documentation/devicetree/bindings/sound/dmic.txt @@ -7,10 +7,12 @@ Required properties: Optional properties: - dmicen-gpios: GPIO specifier for dmic to control start and stop + - num-channels: Number of microphones on this DAI Example node: dmic_codec: dmic@0 { compatible = "dmic-codec"; dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>; + num-channels = <1>; }; diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index b88a1ee66f80..c88f974ebe3e 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -107,8 +107,30 @@ static const struct snd_soc_codec_driver soc_dmic = { static int dmic_dev_probe(struct platform_device *pdev) { + int err; + u32 chans; + struct snd_soc_dai_driver *dai_drv = &dmic_dai; + + if (pdev->dev.of_node) { + err = of_property_read_u32(pdev->dev.of_node, "num-channels", &chans); + if (err && (err != -ENOENT)) + return err; + + if (!err) { + if (chans < 1 || chans > 8) + return -EINVAL; + + dai_drv = devm_kzalloc(&pdev->dev, sizeof(*dai_drv), GFP_KERNEL); + if (!dai_drv) + return -ENOMEM; + + memcpy(dai_drv, &dmic_dai, sizeof(*dai_drv)); + dai_drv->capture.channels_max = chans; + } + } + return snd_soc_register_codec(&pdev->dev, - &soc_dmic, &dmic_dai, 1); + &soc_dmic, dai_drv, 1); } static int dmic_dev_remove(struct platform_device *pdev) -- cgit v1.2.3 From 599522ea10c55c9f6823e3041ce4ddc666965468 Mon Sep 17 00:00:00 2001 From: Steven Eckhoff Date: Mon, 8 Jan 2018 09:47:54 -0700 Subject: ASoC: TSCS42xx: Fix control names The tscs42xx CODEC driver can confuse userspace with non-standard control names. Remove "Switch" from enum control type names. Add "Switch" to on/off control type names. Signed-off-by: Steven Eckhoff Signed-off-by: Mark Brown --- sound/soc/codecs/tscs42xx.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c index eedd600875e5..4a5b32a717f2 100644 --- a/sound/soc/codecs/tscs42xx.c +++ b/sound/soc/codecs/tscs42xx.c @@ -631,7 +631,7 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = { 0, mic_boost_scale), /* Input Channel Map */ - SOC_ENUM("Input Channel Map Switch", ch_map_select_enum), + SOC_ENUM("Input Channel Map", ch_map_select_enum), /* Coefficient Ram */ COEFF_RAM_CTL("Cascade1L BiQuad1", BIQUAD_SIZE, 0x00), @@ -708,13 +708,13 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = { /* EQ */ SOC_SINGLE("EQ1 Switch", R_CONFIG1, FB_CONFIG1_EQ1_EN, 1, 0), SOC_SINGLE("EQ2 Switch", R_CONFIG1, FB_CONFIG1_EQ2_EN, 1, 0), - SOC_ENUM("EQ1 Band Enable Switch", eq1_band_enable_enum), - SOC_ENUM("EQ2 Band Enable Switch", eq2_band_enable_enum), + SOC_ENUM("EQ1 Band Enable", eq1_band_enable_enum), + SOC_ENUM("EQ2 Band Enable", eq2_band_enable_enum), /* CLE */ - SOC_ENUM("CLE Level Detect Switch", + SOC_ENUM("CLE Level Detect", cle_level_detection_enum), - SOC_ENUM("CLE Level Detect Win Switch", + SOC_ENUM("CLE Level Detect Win", cle_level_detection_window_enum), SOC_SINGLE("Expander Switch", R_CLECTL, FB_CLECTL_EXP_EN, 1, 0), @@ -726,7 +726,7 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = { R_MUGAIN, FB_MUGAIN_CLEMUG, 0x1f, 0, mugain_scale), SOC_SINGLE_TLV("Comp Thresh Playback Volume", R_COMPTH, FB_COMPTH, 0xff, 0, compth_scale), - SOC_ENUM("Comp Ratio Switch", compressor_ratio_enum), + SOC_ENUM("Comp Ratio", compressor_ratio_enum), SND_SOC_BYTES("Comp Atk Time", R_CATKTCL, 2), /* Effects */ @@ -740,50 +740,50 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = { SOC_SINGLE("MBC Band1 Switch", R_DACMBCEN, FB_DACMBCEN_MBCEN1, 1, 0), SOC_SINGLE("MBC Band2 Switch", R_DACMBCEN, FB_DACMBCEN_MBCEN2, 1, 0), SOC_SINGLE("MBC Band3 Switch", R_DACMBCEN, FB_DACMBCEN_MBCEN3, 1, 0), - SOC_ENUM("MBC Band1 Level Detect Switch", + SOC_ENUM("MBC Band1 Level Detect", mbc_level_detection_enums[0]), - SOC_ENUM("MBC Band2 Level Detect Switch", + SOC_ENUM("MBC Band2 Level Detect", mbc_level_detection_enums[1]), - SOC_ENUM("MBC Band3 Level Detect Switch", + SOC_ENUM("MBC Band3 Level Detect", mbc_level_detection_enums[2]), - SOC_ENUM("MBC Band1 Level Detect Win Switch", + SOC_ENUM("MBC Band1 Level Detect Win", mbc_level_detection_window_enums[0]), - SOC_ENUM("MBC Band2 Level Detect Win Switch", + SOC_ENUM("MBC Band2 Level Detect Win", mbc_level_detection_window_enums[1]), - SOC_ENUM("MBC Band3 Level Detect Win Switch", + SOC_ENUM("MBC Band3 Level Detect Win", mbc_level_detection_window_enums[2]), - SOC_SINGLE("MBC1 Phase Invert", R_DACMBCMUG1, FB_DACMBCMUG1_PHASE, - 1, 0), + SOC_SINGLE("MBC1 Phase Invert Switch", + R_DACMBCMUG1, FB_DACMBCMUG1_PHASE, 1, 0), SOC_SINGLE_TLV("DAC MBC1 Make-Up Gain Playback Volume", R_DACMBCMUG1, FB_DACMBCMUG1_MUGAIN, 0x1f, 0, mugain_scale), SOC_SINGLE_TLV("DAC MBC1 Comp Thresh Playback Volume", R_DACMBCTHR1, FB_DACMBCTHR1_THRESH, 0xff, 0, compth_scale), - SOC_ENUM("DAC MBC1 Comp Ratio Switch", + SOC_ENUM("DAC MBC1 Comp Ratio", dac_mbc1_compressor_ratio_enum), SND_SOC_BYTES("DAC MBC1 Comp Atk Time", R_DACMBCATK1L, 2), SND_SOC_BYTES("DAC MBC1 Comp Rel Time Const", R_DACMBCREL1L, 2), - SOC_SINGLE("MBC2 Phase Invert", R_DACMBCMUG2, FB_DACMBCMUG2_PHASE, - 1, 0), + SOC_SINGLE("MBC2 Phase Invert Switch", + R_DACMBCMUG2, FB_DACMBCMUG2_PHASE, 1, 0), SOC_SINGLE_TLV("DAC MBC2 Make-Up Gain Playback Volume", R_DACMBCMUG2, FB_DACMBCMUG2_MUGAIN, 0x1f, 0, mugain_scale), SOC_SINGLE_TLV("DAC MBC2 Comp Thresh Playback Volume", R_DACMBCTHR2, FB_DACMBCTHR2_THRESH, 0xff, 0, compth_scale), - SOC_ENUM("DAC MBC2 Comp Ratio Switch", + SOC_ENUM("DAC MBC2 Comp Ratio", dac_mbc2_compressor_ratio_enum), SND_SOC_BYTES("DAC MBC2 Comp Atk Time", R_DACMBCATK2L, 2), SND_SOC_BYTES("DAC MBC2 Comp Rel Time Const", R_DACMBCREL2L, 2), - SOC_SINGLE("MBC3 Phase Invert", R_DACMBCMUG3, FB_DACMBCMUG3_PHASE, - 1, 0), + SOC_SINGLE("MBC3 Phase Invert Switch", + R_DACMBCMUG3, FB_DACMBCMUG3_PHASE, 1, 0), SOC_SINGLE_TLV("DAC MBC3 Make-Up Gain Playback Volume", R_DACMBCMUG3, FB_DACMBCMUG3_MUGAIN, 0x1f, 0, mugain_scale), SOC_SINGLE_TLV("DAC MBC3 Comp Thresh Playback Volume", R_DACMBCTHR3, FB_DACMBCTHR3_THRESH, 0xff, 0, compth_scale), - SOC_ENUM("DAC MBC3 Comp Ratio Switch", + SOC_ENUM("DAC MBC3 Comp Ratio", dac_mbc3_compressor_ratio_enum), SND_SOC_BYTES("DAC MBC3 Comp Atk Time", R_DACMBCATK3L, 2), SND_SOC_BYTES("DAC MBC3 Comp Rel Time Const", -- cgit v1.2.3 From 3511108a790fc8942448556b82046d6de945b80f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 8 Jan 2018 23:14:44 +0000 Subject: ASoC: TSCS42xx: make functions pll_event and dac_event static The functions pll_event and dac_event are local to the source and do not need to be in global scope, so make them static. Cleans up sparse warnings: symbol 'pll_event' was not declared. Should it be static? symbol 'dac_event' was not declared. Should it be static? Signed-off-by: Colin Ian King Reviewed-by: Steven Eckhoff Signed-off-by: Mark Brown --- sound/soc/codecs/tscs42xx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c index 4a5b32a717f2..e7661d0315e6 100644 --- a/sound/soc/codecs/tscs42xx.c +++ b/sound/soc/codecs/tscs42xx.c @@ -355,8 +355,8 @@ static int dapm_micb_event(struct snd_soc_dapm_widget *w, return 0; } -int pll_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static int pll_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); int ret; @@ -369,8 +369,8 @@ int pll_event(struct snd_soc_dapm_widget *w, return ret; } -int dac_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static int dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct tscs42xx *tscs42xx = snd_soc_codec_get_drvdata(codec); -- cgit v1.2.3 From 67dcf8a3e06582cb6b02952335b5612beb97889f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 5 Jan 2018 18:09:33 +0200 Subject: ACPI: utils: Introduce acpi_dev_get_first_match_name() Sometimes the user wants to have device name of the match rather than just checking if device present or not. To make life easier for such users introduce acpi_dev_get_first_match_name() helper based on code for acpi_dev_present(). For example, GPIO driver for Intel Merrifield needs to know the device name of pin control to be able to apply GPIO mapping table to the proper device. To be more consistent with the purpose rename struct acpi_dev_present_info -> struct acpi_dev_match_info acpi_dev_present_cb() -> acpi_dev_match_cb() in the utils.c file. Tested-by: Pierre-Louis Bossart Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/acpi/utils.c | 41 ++++++++++++++++++++++++++++++++++------- include/acpi/acpi_bus.h | 3 +++ include/linux/acpi.h | 6 ++++++ 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 9d49a1acebe3..78db97687f26 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -737,16 +737,17 @@ bool acpi_dev_found(const char *hid) } EXPORT_SYMBOL(acpi_dev_found); -struct acpi_dev_present_info { +struct acpi_dev_match_info { + const char *dev_name; struct acpi_device_id hid[2]; const char *uid; s64 hrv; }; -static int acpi_dev_present_cb(struct device *dev, void *data) +static int acpi_dev_match_cb(struct device *dev, void *data) { struct acpi_device *adev = to_acpi_device(dev); - struct acpi_dev_present_info *match = data; + struct acpi_dev_match_info *match = data; unsigned long long hrv; acpi_status status; @@ -757,6 +758,8 @@ static int acpi_dev_present_cb(struct device *dev, void *data) strcmp(adev->pnp.unique_id, match->uid))) return 0; + match->dev_name = acpi_dev_name(adev); + if (match->hrv == -1) return 1; @@ -789,20 +792,44 @@ static int acpi_dev_present_cb(struct device *dev, void *data) */ bool acpi_dev_present(const char *hid, const char *uid, s64 hrv) { - struct acpi_dev_present_info match = {}; + struct acpi_dev_match_info match = {}; struct device *dev; strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id)); match.uid = uid; match.hrv = hrv; - dev = bus_find_device(&acpi_bus_type, NULL, &match, - acpi_dev_present_cb); - + dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb); return !!dev; } EXPORT_SYMBOL(acpi_dev_present); +/** + * acpi_dev_get_first_match_name - Return name of first match of ACPI device + * @hid: Hardware ID of the device. + * @uid: Unique ID of the device, pass NULL to not check _UID + * @hrv: Hardware Revision of the device, pass -1 to not check _HRV + * + * Return device name if a matching device was present + * at the moment of invocation, or NULL otherwise. + * + * See additional information in acpi_dev_present() as well. + */ +const char * +acpi_dev_get_first_match_name(const char *hid, const char *uid, s64 hrv) +{ + struct acpi_dev_match_info match = {}; + struct device *dev; + + strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id)); + match.uid = uid; + match.hrv = hrv; + + dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb); + return dev ? match.dev_name : NULL; +} +EXPORT_SYMBOL(acpi_dev_get_first_match_name); + /* * acpi_backlight= handling, this is done here rather then in video_detect.c * because __setup cannot be used in modules. diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 79287629c888..c9608b0b80c6 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -91,6 +91,9 @@ acpi_evaluate_dsm_typed(acpi_handle handle, const guid_t *guid, u64 rev, bool acpi_dev_found(const char *hid); bool acpi_dev_present(const char *hid, const char *uid, s64 hrv); +const char * +acpi_dev_get_first_match_name(const char *hid, const char *uid, s64 hrv); + #ifdef CONFIG_ACPI #include diff --git a/include/linux/acpi.h b/include/linux/acpi.h index dc1ebfeeb5ec..d918f1ea84e6 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -640,6 +640,12 @@ static inline bool acpi_dev_present(const char *hid, const char *uid, s64 hrv) return false; } +static inline const char * +acpi_dev_get_first_match_name(const char *hid, const char *uid, s64 hrv) +{ + return NULL; +} + static inline bool is_acpi_node(struct fwnode_handle *fwnode) { return false; -- cgit v1.2.3 From dd1dbf94d2826a045fbbe2649d84b27d48620d56 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 5 Jan 2018 18:09:34 +0200 Subject: gpio: merrifield: Add support of ACPI enabled platforms The driver needs the pin control device name for ACPI. We are looking through ACPI namespace and return first found device based on ACPI HID for Intel Merrifield FLIS (pin control device). Signed-off-by: Andy Shevchenko Acked-by: Mika Westerberg Acked-by: Linus Walleij Signed-off-by: Rafael J. Wysocki --- drivers/gpio/gpio-merrifield.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index dd67a31ac337..c38624ea0251 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -380,9 +381,16 @@ static void mrfld_irq_init_hw(struct mrfld_gpio *priv) } } +static const char *mrfld_gpio_get_pinctrl_dev_name(void) +{ + const char *dev_name = acpi_dev_get_first_match_name("INTC1002", NULL, -1); + return dev_name ? dev_name : "pinctrl-merrifield"; +} + static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) { const struct mrfld_gpio_pinrange *range; + const char *pinctrl_dev_name; struct mrfld_gpio *priv; u32 gpio_base, irq_base; void __iomem *base; @@ -439,10 +447,11 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id return retval; } + pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(); for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) { range = &mrfld_gpio_ranges[i]; retval = gpiochip_add_pin_range(&priv->chip, - "pinctrl-merrifield", + pinctrl_dev_name, range->gpio_base, range->pin_base, range->npins); -- cgit v1.2.3 From e1053262cf318a2bb4a0e1e9c402a3033c669381 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Tue, 9 Jan 2018 21:01:59 -0800 Subject: ASoC: max98373: Added missing blank lines Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 9af0d985d6e9..cb389571b253 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -176,6 +176,7 @@ static int max98373_get_bclk_sel(int bclk) } return 0; } + static int max98373_set_clock(struct snd_soc_codec *codec, struct snd_pcm_hw_params *params) { @@ -270,6 +271,7 @@ static int max98373_dai_hw_params(struct snd_pcm_substream *substream, params_rate(params)); goto err; } + /* set DAI_SR to correct LRCLK frequency */ regmap_update_bits(max98373->regmap, MAX98373_R2027_PCM_SR_SETUP_1, -- cgit v1.2.3 From 3831a5b87ff87a31dba2f212bcecd4f2b8c7c6d4 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Tue, 9 Jan 2018 21:02:00 -0800 Subject: ASoC: max98373: Added TDM off if parameters are all zeroes Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index cb389571b253..ad17bb1fee7b 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -311,7 +311,10 @@ static int max98373_dai_tdm_slot(struct snd_soc_dai *dai, unsigned int mask; int x, slot_found; - max98373->tdm_mode = true; + if (!tx_mask && !rx_mask && !slots && !slot_width) + max98373->tdm_mode = false; + else + max98373->tdm_mode = true; /* BCLK configuration */ bsel = max98373_get_bclk_sel(slots * slot_width); -- cgit v1.2.3 From b6158323bbe706416f8f13912879a429be5cc2a9 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Tue, 9 Jan 2018 21:02:01 -0800 Subject: ASoC: max98373: Modified control names for TLV controls Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index ad17bb1fee7b..31b0864583e8 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -611,13 +611,13 @@ SOC_ENUM("Output Voltage", max98373_out_volt_enum), /* Dynamic Headroom Tracking */ SOC_SINGLE("DHT Switch", MAX98373_R20D4_DHT_EN, MAX98373_DHT_EN_SHIFT, 1, 0), -SOC_SINGLE_TLV("DHT Gain Min", MAX98373_R20D1_DHT_CFG, +SOC_SINGLE_TLV("DHT Min Volume", MAX98373_R20D1_DHT_CFG, MAX98373_DHT_SPK_GAIN_MIN_SHIFT, 9, 0, max98373_dht_spkgain_min_tlv), -SOC_SINGLE_TLV("DHT Rot Pnt", MAX98373_R20D1_DHT_CFG, +SOC_SINGLE_TLV("DHT Rot Pnt Volume", MAX98373_R20D1_DHT_CFG, MAX98373_DHT_ROT_PNT_SHIFT, 15, 0, max98373_dht_rotation_point_tlv), -SOC_SINGLE_TLV("DHT Attack Step", MAX98373_R20D2_DHT_ATTACK_CFG, +SOC_SINGLE_TLV("DHT Attack Step Volume", MAX98373_R20D2_DHT_ATTACK_CFG, MAX98373_DHT_ATTACK_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv), -SOC_SINGLE_TLV("DHT Release Step", MAX98373_R20D3_DHT_RELEASE_CFG, +SOC_SINGLE_TLV("DHT Release Step Volume", MAX98373_R20D3_DHT_RELEASE_CFG, MAX98373_DHT_RELEASE_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv), SOC_ENUM("DHT Attack Rate", max98373_dht_attack_rate_enum), SOC_ENUM("DHT Release Rate", max98373_dht_release_rate_enum), @@ -650,36 +650,36 @@ SOC_SINGLE("BDE Thresh Hysteresis", MAX98373_R209B_BDE_THRESH_HYST, 0, 0xFF, 0), SOC_SINGLE("BDE Hold Time", MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0), SOC_SINGLE("BDE Attack Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 4, 0xF, 0), SOC_SINGLE("BDE Release Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 0, 0xF, 0), -SOC_SINGLE_TLV("BDE LVL1 Clip Thresh", MAX98373_R20A9_BDE_L1_CFG_2, +SOC_SINGLE_TLV("BDE LVL1 Clip Thresh Volume", MAX98373_R20A9_BDE_L1_CFG_2, 0, 0x3C, 0, max98373_bde_gain_tlv), -SOC_SINGLE_TLV("BDE LVL2 Clip Thresh", MAX98373_R20AC_BDE_L2_CFG_2, +SOC_SINGLE_TLV("BDE LVL2 Clip Thresh Volume", MAX98373_R20AC_BDE_L2_CFG_2, 0, 0x3C, 0, max98373_bde_gain_tlv), -SOC_SINGLE_TLV("BDE LVL3 Clip Thresh", MAX98373_R20AF_BDE_L3_CFG_2, +SOC_SINGLE_TLV("BDE LVL3 Clip Thresh Volume", MAX98373_R20AF_BDE_L3_CFG_2, 0, 0x3C, 0, max98373_bde_gain_tlv), -SOC_SINGLE_TLV("BDE LVL4 Clip Thresh", MAX98373_R20B2_BDE_L4_CFG_2, +SOC_SINGLE_TLV("BDE LVL4 Clip Thresh Volume", MAX98373_R20B2_BDE_L4_CFG_2, 0, 0x3C, 0, max98373_bde_gain_tlv), -SOC_SINGLE_TLV("BDE LVL1 Clip Gain Reduct", MAX98373_R20AA_BDE_L1_CFG_3, +SOC_SINGLE_TLV("BDE LVL1 Clip Reduction Volume", MAX98373_R20AA_BDE_L1_CFG_3, 0, 0x3C, 0, max98373_bde_gain_tlv), -SOC_SINGLE_TLV("BDE LVL2 Clip Gain Reduct", MAX98373_R20AD_BDE_L2_CFG_3, +SOC_SINGLE_TLV("BDE LVL2 Clip Reduction Volume", MAX98373_R20AD_BDE_L2_CFG_3, 0, 0x3C, 0, max98373_bde_gain_tlv), -SOC_SINGLE_TLV("BDE LVL3 Clip Gain Reduct", MAX98373_R20B0_BDE_L3_CFG_3, +SOC_SINGLE_TLV("BDE LVL3 Clip Reduction Volume", MAX98373_R20B0_BDE_L3_CFG_3, 0, 0x3C, 0, max98373_bde_gain_tlv), -SOC_SINGLE_TLV("BDE LVL4 Clip Gain Reduct", MAX98373_R20B3_BDE_L4_CFG_3, +SOC_SINGLE_TLV("BDE LVL4 Clip Reduction Volume", MAX98373_R20B3_BDE_L4_CFG_3, 0, 0x3C, 0, max98373_bde_gain_tlv), -SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh", MAX98373_R20A8_BDE_L1_CFG_1, +SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh Volume", MAX98373_R20A8_BDE_L1_CFG_1, 0, 0xF, 0, max98373_limiter_thresh_tlv), -SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh", MAX98373_R20AB_BDE_L2_CFG_1, +SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh Volume", MAX98373_R20AB_BDE_L2_CFG_1, 0, 0xF, 0, max98373_limiter_thresh_tlv), -SOC_SINGLE_TLV("BDE LVL3 Limiter Thresh", MAX98373_R20AE_BDE_L3_CFG_1, +SOC_SINGLE_TLV("BDE LVL3 Limiter Thresh Volume", MAX98373_R20AE_BDE_L3_CFG_1, 0, 0xF, 0, max98373_limiter_thresh_tlv), -SOC_SINGLE_TLV("BDE LVL4 Limiter Thresh", MAX98373_R20B1_BDE_L4_CFG_1, +SOC_SINGLE_TLV("BDE LVL4 Limiter Thresh Volume", MAX98373_R20B1_BDE_L4_CFG_1, 0, 0xF, 0, max98373_limiter_thresh_tlv), /* Limiter */ SOC_SINGLE("Limiter Switch", MAX98373_R20E2_LIMITER_EN, MAX98373_LIMITER_EN_SHIFT, 1, 0), SOC_SINGLE("Limiter Src Switch", MAX98373_R20E0_LIMITER_THRESH_CFG, MAX98373_LIMITER_THRESH_SRC_SHIFT, 1, 0), -SOC_SINGLE_TLV("Limiter Thresh", MAX98373_R20E0_LIMITER_THRESH_CFG, +SOC_SINGLE_TLV("Limiter Thresh Volume", MAX98373_R20E0_LIMITER_THRESH_CFG, MAX98373_LIMITER_THRESH_SHIFT, 15, 0, max98373_limiter_thresh_tlv), SOC_ENUM("Limiter Attack Rate", max98373_limiter_attack_rate_enum), SOC_ENUM("Limiter Release Rate", max98373_limiter_release_rate_enum), -- cgit v1.2.3 From 48b66f8f936f369bb1a43c12aedbfeb2975baf4c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 10 Jan 2018 11:13:03 +0100 Subject: iio: Add hardware consumer buffer support Hardware consumer interface can be used when one IIO device has a direct connection to another device in hardware. Signed-off-by: Lars-Peter Clausen Signed-off-by: Arnaud Pouliquen Reviewed-by: Jonathan Cameron Signed-off-by: Mark Brown --- drivers/iio/buffer/Kconfig | 10 ++ drivers/iio/buffer/Makefile | 1 + drivers/iio/buffer/industrialio-hw-consumer.c | 181 ++++++++++++++++++++++++++ include/linux/iio/hw-consumer.h | 19 +++ 4 files changed, 211 insertions(+) create mode 100644 drivers/iio/buffer/industrialio-hw-consumer.c create mode 100644 include/linux/iio/hw-consumer.h diff --git a/drivers/iio/buffer/Kconfig b/drivers/iio/buffer/Kconfig index 4ffd3db7817f..338774cba19b 100644 --- a/drivers/iio/buffer/Kconfig +++ b/drivers/iio/buffer/Kconfig @@ -29,6 +29,16 @@ config IIO_BUFFER_DMAENGINE Should be selected by drivers that want to use this functionality. +config IIO_BUFFER_HW_CONSUMER + tristate "Industrial I/O HW buffering" + help + Provides a way to bonding when an IIO device has a direct connection + to another device in hardware. In this case buffers for data transfers + are handled by hardware. + + Should be selected by drivers that want to use the generic Hw consumer + interface. + config IIO_KFIFO_BUF tristate "Industrial I/O buffering based on kfifo" help diff --git a/drivers/iio/buffer/Makefile b/drivers/iio/buffer/Makefile index 95f9f41c58b7..1403eb2f9409 100644 --- a/drivers/iio/buffer/Makefile +++ b/drivers/iio/buffer/Makefile @@ -7,5 +7,6 @@ obj-$(CONFIG_IIO_BUFFER_CB) += industrialio-buffer-cb.o obj-$(CONFIG_IIO_BUFFER_DMA) += industrialio-buffer-dma.o obj-$(CONFIG_IIO_BUFFER_DMAENGINE) += industrialio-buffer-dmaengine.o +obj-$(CONFIG_IIO_BUFFER_HW_CONSUMER) += industrialio-hw-consumer.o obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c b/drivers/iio/buffer/industrialio-hw-consumer.c new file mode 100644 index 000000000000..993ecdcdab64 --- /dev/null +++ b/drivers/iio/buffer/industrialio-hw-consumer.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2017 Analog Devices Inc. + * Author: Lars-Peter Clausen + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +/** + * struct iio_hw_consumer - IIO hw consumer block + * @buffers: hardware buffers list head. + * @channels: IIO provider channels. + */ +struct iio_hw_consumer { + struct list_head buffers; + struct iio_channel *channels; +}; + +struct hw_consumer_buffer { + struct list_head head; + struct iio_dev *indio_dev; + struct iio_buffer buffer; + long scan_mask[]; +}; + +static struct hw_consumer_buffer *iio_buffer_to_hw_consumer_buffer( + struct iio_buffer *buffer) +{ + return container_of(buffer, struct hw_consumer_buffer, buffer); +} + +static void iio_hw_buf_release(struct iio_buffer *buffer) +{ + struct hw_consumer_buffer *hw_buf = + iio_buffer_to_hw_consumer_buffer(buffer); + kfree(hw_buf); +} + +static const struct iio_buffer_access_funcs iio_hw_buf_access = { + .release = &iio_hw_buf_release, + .modes = INDIO_BUFFER_HARDWARE, +}; + +static struct hw_consumer_buffer *iio_hw_consumer_get_buffer( + struct iio_hw_consumer *hwc, struct iio_dev *indio_dev) +{ + size_t mask_size = BITS_TO_LONGS(indio_dev->masklength) * sizeof(long); + struct hw_consumer_buffer *buf; + + list_for_each_entry(buf, &hwc->buffers, head) { + if (buf->indio_dev == indio_dev) + return buf; + } + + buf = kzalloc(sizeof(*buf) + mask_size, GFP_KERNEL); + if (!buf) + return NULL; + + buf->buffer.access = &iio_hw_buf_access; + buf->indio_dev = indio_dev; + buf->buffer.scan_mask = buf->scan_mask; + + iio_buffer_init(&buf->buffer); + list_add_tail(&buf->head, &hwc->buffers); + + return buf; +} + +/** + * iio_hw_consumer_alloc() - Allocate IIO hardware consumer + * @dev: Pointer to consumer device. + * + * Returns a valid iio_hw_consumer on success or a ERR_PTR() on failure. + */ +struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev) +{ + struct hw_consumer_buffer *buf; + struct iio_hw_consumer *hwc; + struct iio_channel *chan; + int ret; + + hwc = kzalloc(sizeof(*hwc), GFP_KERNEL); + if (!hwc) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&hwc->buffers); + + hwc->channels = iio_channel_get_all(dev); + if (IS_ERR(hwc->channels)) { + ret = PTR_ERR(hwc->channels); + goto err_free_hwc; + } + + chan = &hwc->channels[0]; + while (chan->indio_dev) { + buf = iio_hw_consumer_get_buffer(hwc, chan->indio_dev); + if (!buf) { + ret = -ENOMEM; + goto err_put_buffers; + } + set_bit(chan->channel->scan_index, buf->buffer.scan_mask); + chan++; + } + + return hwc; + +err_put_buffers: + list_for_each_entry(buf, &hwc->buffers, head) + iio_buffer_put(&buf->buffer); + iio_channel_release_all(hwc->channels); +err_free_hwc: + kfree(hwc); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(iio_hw_consumer_alloc); + +/** + * iio_hw_consumer_free() - Free IIO hardware consumer + * @hwc: hw consumer to free. + */ +void iio_hw_consumer_free(struct iio_hw_consumer *hwc) +{ + struct hw_consumer_buffer *buf, *n; + + iio_channel_release_all(hwc->channels); + list_for_each_entry_safe(buf, n, &hwc->buffers, head) + iio_buffer_put(&buf->buffer); + kfree(hwc); +} +EXPORT_SYMBOL_GPL(iio_hw_consumer_free); + +/** + * iio_hw_consumer_enable() - Enable IIO hardware consumer + * @hwc: iio_hw_consumer to enable. + * + * Returns 0 on success. + */ +int iio_hw_consumer_enable(struct iio_hw_consumer *hwc) +{ + struct hw_consumer_buffer *buf; + int ret; + + list_for_each_entry(buf, &hwc->buffers, head) { + ret = iio_update_buffers(buf->indio_dev, &buf->buffer, NULL); + if (ret) + goto err_disable_buffers; + } + + return 0; + +err_disable_buffers: + list_for_each_entry_continue_reverse(buf, &hwc->buffers, head) + iio_update_buffers(buf->indio_dev, NULL, &buf->buffer); + return ret; +} +EXPORT_SYMBOL_GPL(iio_hw_consumer_enable); + +/** + * iio_hw_consumer_disable() - Disable IIO hardware consumer + * @hwc: iio_hw_consumer to disable. + */ +void iio_hw_consumer_disable(struct iio_hw_consumer *hwc) +{ + struct hw_consumer_buffer *buf; + + list_for_each_entry(buf, &hwc->buffers, head) + iio_update_buffers(buf->indio_dev, NULL, &buf->buffer); +} +EXPORT_SYMBOL_GPL(iio_hw_consumer_disable); + +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("Hardware consumer buffer the IIO framework"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/iio/hw-consumer.h b/include/linux/iio/hw-consumer.h new file mode 100644 index 000000000000..db8c00b9c7a5 --- /dev/null +++ b/include/linux/iio/hw-consumer.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Industrial I/O in kernel hardware consumer interface + * + * Copyright 2017 Analog Devices Inc. + * Author: Lars-Peter Clausen + */ + +#ifndef LINUX_IIO_HW_CONSUMER_H +#define LINUX_IIO_HW_CONSUMER_H + +struct iio_hw_consumer; + +struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev); +void iio_hw_consumer_free(struct iio_hw_consumer *hwc); +int iio_hw_consumer_enable(struct iio_hw_consumer *hwc); +void iio_hw_consumer_disable(struct iio_hw_consumer *hwc); + +#endif -- cgit v1.2.3 From 5b178943d64b85d78350ea9c86344c376d7bfe74 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Wed, 10 Jan 2018 11:13:04 +0100 Subject: docs: driver-api: add iio hw consumer section This adds a section about the Hardware consumer API of the IIO subsystem to the driver API documentation. Signed-off-by: Arnaud Pouliquen Reviewed-by: Jonathan Cameron Signed-off-by: Mark Brown --- Documentation/driver-api/iio/hw-consumer.rst | 51 ++++++++++++++++++++++++++++ Documentation/driver-api/iio/index.rst | 1 + 2 files changed, 52 insertions(+) create mode 100644 Documentation/driver-api/iio/hw-consumer.rst diff --git a/Documentation/driver-api/iio/hw-consumer.rst b/Documentation/driver-api/iio/hw-consumer.rst new file mode 100644 index 000000000000..8facce6a6733 --- /dev/null +++ b/Documentation/driver-api/iio/hw-consumer.rst @@ -0,0 +1,51 @@ +=========== +HW consumer +=========== +An IIO device can be directly connected to another device in hardware. in this +case the buffers between IIO provider and IIO consumer are handled by hardware. +The Industrial I/O HW consumer offers a way to bond these IIO devices without +software buffer for data. The implementation can be found under +:file:`drivers/iio/buffer/hw-consumer.c` + + +* struct :c:type:`iio_hw_consumer` — Hardware consumer structure +* :c:func:`iio_hw_consumer_alloc` — Allocate IIO hardware consumer +* :c:func:`iio_hw_consumer_free` — Free IIO hardware consumer +* :c:func:`iio_hw_consumer_enable` — Enable IIO hardware consumer +* :c:func:`iio_hw_consumer_disable` — Disable IIO hardware consumer + + +HW consumer setup +================= + +As standard IIO device the implementation is based on IIO provider/consumer. +A typical IIO HW consumer setup looks like this:: + + static struct iio_hw_consumer *hwc; + + static const struct iio_info adc_info = { + .read_raw = adc_read_raw, + }; + + static int adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) + { + ret = iio_hw_consumer_enable(hwc); + + /* Acquire data */ + + ret = iio_hw_consumer_disable(hwc); + } + + static int adc_probe(struct platform_device *pdev) + { + hwc = devm_iio_hw_consumer_alloc(&iio->dev); + } + +More details +============ +.. kernel-doc:: include/linux/iio/hw-consumer.h +.. kernel-doc:: drivers/iio/buffer/industrialio-hw-consumer.c + :export: + diff --git a/Documentation/driver-api/iio/index.rst b/Documentation/driver-api/iio/index.rst index e5c3922d1b6f..7fba341bd8b2 100644 --- a/Documentation/driver-api/iio/index.rst +++ b/Documentation/driver-api/iio/index.rst @@ -15,3 +15,4 @@ Contents: buffers triggers triggered-buffers + hw-consumer -- cgit v1.2.3 From b688c18d30060e8a840d8af72790339c72acdac4 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Wed, 10 Jan 2018 11:13:05 +0100 Subject: IIO: hw_consumer: add devm_iio_hw_consumer_alloc Add devm_iio_hw_consumer_alloc function that calls iio_hw_consumer_free when the device is unbound from the bus. Signed-off-by: Arnaud Pouliquen Reviewed-by: Jonathan Cameron Signed-off-by: Mark Brown --- drivers/iio/buffer/industrialio-hw-consumer.c | 66 +++++++++++++++++++++++++++ include/linux/iio/hw-consumer.h | 2 + 2 files changed, 68 insertions(+) diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c b/drivers/iio/buffer/industrialio-hw-consumer.c index 993ecdcdab64..95165697d8ae 100644 --- a/drivers/iio/buffer/industrialio-hw-consumer.c +++ b/drivers/iio/buffer/industrialio-hw-consumer.c @@ -137,6 +137,72 @@ void iio_hw_consumer_free(struct iio_hw_consumer *hwc) } EXPORT_SYMBOL_GPL(iio_hw_consumer_free); +static void devm_iio_hw_consumer_release(struct device *dev, void *res) +{ + iio_hw_consumer_free(*(struct iio_hw_consumer **)res); +} + +static int devm_iio_hw_consumer_match(struct device *dev, void *res, void *data) +{ + struct iio_hw_consumer **r = res; + + if (!r || !*r) { + WARN_ON(!r || !*r); + return 0; + } + return *r == data; +} + +/** + * devm_iio_hw_consumer_alloc - Resource-managed iio_hw_consumer_alloc() + * @dev: Pointer to consumer device. + * + * Managed iio_hw_consumer_alloc. iio_hw_consumer allocated with this function + * is automatically freed on driver detach. + * + * If an iio_hw_consumer allocated with this function needs to be freed + * separately, devm_iio_hw_consumer_free() must be used. + * + * returns pointer to allocated iio_hw_consumer on success, NULL on failure. + */ +struct iio_hw_consumer *devm_iio_hw_consumer_alloc(struct device *dev) +{ + struct iio_hw_consumer **ptr, *iio_hwc; + + ptr = devres_alloc(devm_iio_hw_consumer_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return NULL; + + iio_hwc = iio_hw_consumer_alloc(dev); + if (IS_ERR(iio_hwc)) { + devres_free(ptr); + } else { + *ptr = iio_hwc; + devres_add(dev, ptr); + } + + return iio_hwc; +} +EXPORT_SYMBOL_GPL(devm_iio_hw_consumer_alloc); + +/** + * devm_iio_hw_consumer_free - Resource-managed iio_hw_consumer_free() + * @dev: Pointer to consumer device. + * @hwc: iio_hw_consumer to free. + * + * Free iio_hw_consumer allocated with devm_iio_hw_consumer_alloc(). + */ +void devm_iio_hw_consumer_free(struct device *dev, struct iio_hw_consumer *hwc) +{ + int rc; + + rc = devres_release(dev, devm_iio_hw_consumer_release, + devm_iio_hw_consumer_match, hwc); + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_iio_hw_consumer_free); + /** * iio_hw_consumer_enable() - Enable IIO hardware consumer * @hwc: iio_hw_consumer to enable. diff --git a/include/linux/iio/hw-consumer.h b/include/linux/iio/hw-consumer.h index db8c00b9c7a5..44d48bb1d39f 100644 --- a/include/linux/iio/hw-consumer.h +++ b/include/linux/iio/hw-consumer.h @@ -13,6 +13,8 @@ struct iio_hw_consumer; struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev); void iio_hw_consumer_free(struct iio_hw_consumer *hwc); +struct iio_hw_consumer *devm_iio_hw_consumer_alloc(struct device *dev); +void devm_iio_hw_consumer_free(struct device *dev, struct iio_hw_consumer *hwc); int iio_hw_consumer_enable(struct iio_hw_consumer *hwc); void iio_hw_consumer_disable(struct iio_hw_consumer *hwc); -- cgit v1.2.3 From 34739a213dbb85c8d775de42d52358255059c257 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Wed, 10 Jan 2018 11:13:06 +0100 Subject: IIO: inkern: API for manipulating channel attributes Extend the inkern API with functions for reading and writing attribute of iio channels. Signed-off-by: Arnaud Pouliquen Reviewed-by: Jonathan Cameron Signed-off-by: Mark Brown --- drivers/iio/inkern.c | 17 ++++++++++++----- include/linux/iio/consumer.h | 26 ++++++++++++++++++++++++++ include/linux/iio/iio.h | 28 ---------------------------- include/linux/iio/types.h | 28 ++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 33 deletions(-) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 069defcc6d9b..ec98790e2a28 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -664,9 +664,8 @@ err_unlock: } EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed); -static int iio_read_channel_attribute(struct iio_channel *chan, - int *val, int *val2, - enum iio_chan_info_enum attribute) +int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2, + enum iio_chan_info_enum attribute) { int ret; @@ -682,6 +681,7 @@ err_unlock: return ret; } +EXPORT_SYMBOL_GPL(iio_read_channel_attribute); int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2) { @@ -850,7 +850,8 @@ static int iio_channel_write(struct iio_channel *chan, int val, int val2, chan->channel, val, val2, info); } -int iio_write_channel_raw(struct iio_channel *chan, int val) +int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2, + enum iio_chan_info_enum attribute) { int ret; @@ -860,12 +861,18 @@ int iio_write_channel_raw(struct iio_channel *chan, int val) goto err_unlock; } - ret = iio_channel_write(chan, val, 0, IIO_CHAN_INFO_RAW); + ret = iio_channel_write(chan, val, val2, attribute); err_unlock: mutex_unlock(&chan->indio_dev->info_exist_lock); return ret; } +EXPORT_SYMBOL_GPL(iio_write_channel_attribute); + +int iio_write_channel_raw(struct iio_channel *chan, int val) +{ + return iio_write_channel_attribute(chan, val, 0, IIO_CHAN_INFO_RAW); +} EXPORT_SYMBOL_GPL(iio_write_channel_raw); unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan) diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 5e347a9805fd..2017f35db17c 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -215,6 +215,32 @@ int iio_read_channel_average_raw(struct iio_channel *chan, int *val); */ int iio_read_channel_processed(struct iio_channel *chan, int *val); +/** + * iio_write_channel_attribute() - Write values to the device attribute. + * @chan: The channel being queried. + * @val: Value being written. + * @val2: Value being written.val2 use depends on attribute type. + * @attribute: info attribute to be read. + * + * Returns an error code or 0. + */ +int iio_write_channel_attribute(struct iio_channel *chan, int val, + int val2, enum iio_chan_info_enum attribute); + +/** + * iio_read_channel_attribute() - Read values from the device attribute. + * @chan: The channel being queried. + * @val: Value being written. + * @val2: Value being written.Val2 use depends on attribute type. + * @attribute: info attribute to be written. + * + * Returns an error code if failed. Else returns a description of what is in val + * and val2, such as IIO_VAL_INT_PLUS_MICRO telling us we have a value of val + * + val2/1e6 + */ +int iio_read_channel_attribute(struct iio_channel *chan, int *val, + int *val2, enum iio_chan_info_enum attribute); + /** * iio_write_channel_raw() - write to a given channel * @chan: The channel being queried. diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 20b61347ea58..f12a61be1ede 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -20,34 +20,6 @@ * Currently assumes nano seconds. */ -enum iio_chan_info_enum { - IIO_CHAN_INFO_RAW = 0, - IIO_CHAN_INFO_PROCESSED, - IIO_CHAN_INFO_SCALE, - IIO_CHAN_INFO_OFFSET, - IIO_CHAN_INFO_CALIBSCALE, - IIO_CHAN_INFO_CALIBBIAS, - IIO_CHAN_INFO_PEAK, - IIO_CHAN_INFO_PEAK_SCALE, - IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW, - IIO_CHAN_INFO_AVERAGE_RAW, - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY, - IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY, - IIO_CHAN_INFO_SAMP_FREQ, - IIO_CHAN_INFO_FREQUENCY, - IIO_CHAN_INFO_PHASE, - IIO_CHAN_INFO_HARDWAREGAIN, - IIO_CHAN_INFO_HYSTERESIS, - IIO_CHAN_INFO_INT_TIME, - IIO_CHAN_INFO_ENABLE, - IIO_CHAN_INFO_CALIBHEIGHT, - IIO_CHAN_INFO_CALIBWEIGHT, - IIO_CHAN_INFO_DEBOUNCE_COUNT, - IIO_CHAN_INFO_DEBOUNCE_TIME, - IIO_CHAN_INFO_CALIBEMISSIVITY, - IIO_CHAN_INFO_OVERSAMPLING_RATIO, -}; - enum iio_shared_by { IIO_SEPARATE, IIO_SHARED_BY_TYPE, diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 2aa7b6384d64..6eb3d683ef62 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -34,4 +34,32 @@ enum iio_available_type { IIO_AVAIL_RANGE, }; +enum iio_chan_info_enum { + IIO_CHAN_INFO_RAW = 0, + IIO_CHAN_INFO_PROCESSED, + IIO_CHAN_INFO_SCALE, + IIO_CHAN_INFO_OFFSET, + IIO_CHAN_INFO_CALIBSCALE, + IIO_CHAN_INFO_CALIBBIAS, + IIO_CHAN_INFO_PEAK, + IIO_CHAN_INFO_PEAK_SCALE, + IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW, + IIO_CHAN_INFO_AVERAGE_RAW, + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY, + IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY, + IIO_CHAN_INFO_SAMP_FREQ, + IIO_CHAN_INFO_FREQUENCY, + IIO_CHAN_INFO_PHASE, + IIO_CHAN_INFO_HARDWAREGAIN, + IIO_CHAN_INFO_HYSTERESIS, + IIO_CHAN_INFO_INT_TIME, + IIO_CHAN_INFO_ENABLE, + IIO_CHAN_INFO_CALIBHEIGHT, + IIO_CHAN_INFO_CALIBWEIGHT, + IIO_CHAN_INFO_DEBOUNCE_COUNT, + IIO_CHAN_INFO_DEBOUNCE_TIME, + IIO_CHAN_INFO_CALIBEMISSIVITY, + IIO_CHAN_INFO_OVERSAMPLING_RATIO, +}; + #endif /* _IIO_TYPES_H_ */ -- cgit v1.2.3 From af11143757b7995f185e9365d8450ea9d63ea267 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Wed, 10 Jan 2018 11:13:07 +0100 Subject: IIO: Add DT bindings for sigma delta adc modulator Add documentation of device tree bindings to support sigma delta modulator in IIO framework. Signed-off-by: Arnaud Pouliquen Acked-by: Rob Herring Acked-by: Jonathan Cameron Signed-off-by: Mark Brown --- .../devicetree/bindings/iio/adc/sigma-delta-modulator.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt diff --git a/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt b/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt new file mode 100644 index 000000000000..e9ebb8a20e0d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt @@ -0,0 +1,13 @@ +Device-Tree bindings for sigma delta modulator + +Required properties: +- compatible: should be "ads1201", "sd-modulator". "sd-modulator" can be use + as a generic SD modulator if modulator not specified in compatible list. +- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers". + +Example node: + + ads1202: adc@0 { + compatible = "sd-modulator"; + #io-channel-cells = <1>; + }; -- cgit v1.2.3 From 8a5f0b6f6c4f1a0ff98b5ca1f83cbe34cdebd96e Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Wed, 10 Jan 2018 11:13:08 +0100 Subject: IIO: ADC: add sigma delta modulator support Add generic driver to support sigma delta modulators. Typically, this device is hardware connected to an IIO device in charge of the conversion. Devices are bonded through the hardware consumer API. Signed-off-by: Arnaud Pouliquen Acked-by: Jonathan Cameron Signed-off-by: Mark Brown --- drivers/iio/adc/Kconfig | 12 +++++++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/sd_adc_modulator.c | 68 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 drivers/iio/adc/sd_adc_modulator.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index ef86296b8b0d..5f9d04a8ba53 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -629,6 +629,18 @@ config SPEAR_ADC To compile this driver as a module, choose M here: the module will be called spear_adc. +config SD_ADC_MODULATOR + tristate "Generic sigma delta modulator" + depends on OF + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Select this option to enables sigma delta modulator. This driver can + support generic sigma delta modulators. + + This driver can also be built as a module. If so, the module + will be called sd_adc_modulator. + config STM32_ADC_CORE tristate "STMicroelectronics STM32 adc core" depends on ARCH_STM32 || COMPILE_TEST diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 9572c1090f35..fa5e7949f642 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -82,3 +82,4 @@ obj-$(CONFIG_VF610_ADC) += vf610_adc.o obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o +obj-$(CONFIG_SD_ADC_MODULATOR) += sd_adc_modulator.o diff --git a/drivers/iio/adc/sd_adc_modulator.c b/drivers/iio/adc/sd_adc_modulator.c new file mode 100644 index 000000000000..560d8c7d9d86 --- /dev/null +++ b/drivers/iio/adc/sd_adc_modulator.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Generic sigma delta modulator driver + * + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author: Arnaud Pouliquen . + */ + +#include +#include +#include +#include + +static const struct iio_info iio_sd_mod_iio_info; + +static const struct iio_chan_spec iio_sd_mod_ch = { + .type = IIO_VOLTAGE, + .indexed = 1, + .scan_type = { + .sign = 'u', + .realbits = 1, + .shift = 0, + }, +}; + +static int iio_sd_mod_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct iio_dev *iio; + + iio = devm_iio_device_alloc(dev, 0); + if (!iio) + return -ENOMEM; + + iio->dev.parent = dev; + iio->dev.of_node = dev->of_node; + iio->name = dev_name(dev); + iio->info = &iio_sd_mod_iio_info; + iio->modes = INDIO_BUFFER_HARDWARE; + + iio->num_channels = 1; + iio->channels = &iio_sd_mod_ch; + + platform_set_drvdata(pdev, iio); + + return devm_iio_device_register(&pdev->dev, iio); +} + +static const struct of_device_id sd_adc_of_match[] = { + { .compatible = "sd-modulator" }, + { .compatible = "ads1201" }, + { } +}; +MODULE_DEVICE_TABLE(of, sd_adc_of_match); + +static struct platform_driver iio_sd_mod_adc = { + .driver = { + .name = "iio_sd_adc_mod", + .of_match_table = of_match_ptr(sd_adc_of_match), + }, + .probe = iio_sd_mod_probe, +}; + +module_platform_driver(iio_sd_mod_adc); + +MODULE_DESCRIPTION("Basic sigma delta modulator"); +MODULE_AUTHOR("Arnaud Pouliquen "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 6c82f947fc9784b774cad0b90c20a5d703f9b763 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Wed, 10 Jan 2018 11:13:09 +0100 Subject: IIO: add DT bindings for stm32 DFSDM filter Add bindings that describes STM32 Digital Filter for Sigma Delta Modulators. DFSDM allows to connect sigma delta modulators. Signed-off-by: Arnaud Pouliquen Acked-by: Rob Herring Acked-by: Jonathan Cameron Signed-off-by: Mark Brown --- .../bindings/iio/adc/st,stm32-dfsdm-adc.txt | 128 +++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt new file mode 100644 index 000000000000..911492da48f3 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt @@ -0,0 +1,128 @@ +STMicroelectronics STM32 DFSDM ADC device driver + + +STM32 DFSDM ADC is a sigma delta analog-to-digital converter dedicated to +interface external sigma delta modulators to STM32 micro controllers. +It is mainly targeted for: +- Sigma delta modulators (motor control, metering...) +- PDM microphones (audio digital microphone) + +It features up to 8 serial digital interfaces (SPI or Manchester) and +up to 4 filters on stm32h7. + +Each child node match with a filter instance. + +Contents of a STM32 DFSDM root node: +------------------------------------ +Required properties: +- compatible: Should be "st,stm32h7-dfsdm". +- reg: Offset and length of the DFSDM block register set. +- clocks: IP and serial interfaces clocking. Should be set according + to rcc clock ID and "clock-names". +- clock-names: Input clock name "dfsdm" must be defined, + "audio" is optional. If defined CLKOUT is based on the audio + clock, else "dfsdm" is used. +- #interrupt-cells = <1>; +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties: +- spi-max-frequency: Requested only for SPI master mode. + SPI clock OUT frequency (Hz). This clock must be set according + to "clock" property. Frequency must be a multiple of the rcc + clock frequency. If not, SPI CLKOUT frequency will not be + accurate. + +Contents of a STM32 DFSDM child nodes: +-------------------------------------- + +Required properties: +- compatible: Must be: + "st,stm32-dfsdm-adc" for sigma delta ADCs + "st,stm32-dfsdm-dmic" for audio digital microphone. +- reg: Specifies the DFSDM filter instance used. +- interrupts: IRQ lines connected to each DFSDM filter instance. +- st,adc-channels: List of single-ended channels muxed for this ADC. + valid values: + "st,stm32h7-dfsdm" compatibility: 0 to 7. +- st,adc-channel-names: List of single-ended channel names. +- st,filter-order: SinC filter order from 0 to 5. + 0: FastSinC + [1-5]: order 1 to 5. + For audio purpose it is recommended to use order 3 to 5. +- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers". + +Required properties for "st,stm32-dfsdm-adc" compatibility: +- io-channels: From common IIO binding. Used to pipe external sigma delta + modulator or internal ADC output to DFSDM channel. + This is not required for "st,stm32-dfsdm-pdm" compatibility as + PDM microphone is binded in Audio DT node. + +Required properties for "st,stm32-dfsdm-pdm" compatibility: +- #sound-dai-cells: Must be set to 0. +- dma: DMA controller phandle and DMA request line associated to the + filter instance (specified by the field "reg") +- dma-names: Must be "rx" + +Optional properties: +- st,adc-channel-types: Single-ended channel input type. + - "SPI_R": SPI with data on rising edge (default) + - "SPI_F": SPI with data on falling edge + - "MANCH_R": manchester codec, rising edge = logic 0 + - "MANCH_F": manchester codec, falling edge = logic 1 +- st,adc-channel-clk-src: Conversion clock source. + - "CLKIN": external SPI clock (CLKIN x) + - "CLKOUT": internal SPI clock (CLKOUT) (default) + - "CLKOUT_F": internal SPI clock divided by 2 (falling edge). + - "CLKOUT_R": internal SPI clock divided by 2 (rising edge). + +- st,adc-alt-channel: Must be defined if two sigma delta modulator are + connected on same SPI input. + If not set, channel n is connected to SPI input n. + If set, channel n is connected to SPI input n + 1. + +- st,filter0-sync: Set to 1 to synchronize with DFSDM filter instance 0. + Used for multi microphones synchronization. + +Example of a sigma delta adc connected on DFSDM SPI port 0 +and a pdm microphone connected on DFSDM SPI port 1: + + ads1202: simple_sd_adc@0 { + compatible = "ads1202"; + #io-channel-cells = <1>; + }; + + dfsdm: dfsdm@40017000 { + compatible = "st,stm32h7-dfsdm"; + reg = <0x40017000 0x400>; + clocks = <&rcc DFSDM1_CK>; + clock-names = "dfsdm"; + #interrupt-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + dfsdm_adc0: filter@0 { + compatible = "st,stm32-dfsdm-adc"; + #io-channel-cells = <1>; + reg = <0>; + interrupts = <110>; + st,adc-channels = <0>; + st,adc-channel-names = "sd_adc0"; + st,adc-channel-types = "SPI_F"; + st,adc-channel-clk-src = "CLKOUT"; + io-channels = <&ads1202 0>; + st,filter-order = <3>; + }; + dfsdm_pdm1: filter@1 { + compatible = "st,stm32-dfsdm-dmic"; + reg = <1>; + interrupts = <111>; + dmas = <&dmamux1 102 0x400 0x00>; + dma-names = "rx"; + st,adc-channels = <1>; + st,adc-channel-names = "dmic1"; + st,adc-channel-types = "SPI_R"; + st,adc-channel-clk-src = "CLKOUT"; + st,filter-order = <5>; + }; + } -- cgit v1.2.3 From bed73904e76fc08d0ec3a7ba3eb2ddbb2e38862c Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Wed, 10 Jan 2018 11:13:10 +0100 Subject: IIO: ADC: add stm32 DFSDM core support Add driver for stm32 DFSDM pheripheral. Its converts a sigma delta stream in n bit samples through a low pass filter and an integrator. stm32-dfsdm-core driver is the core part supporting the filter instances dedicated to sigma-delta ADC or audio PDM microphone purpose. Signed-off-by: Arnaud Pouliquen Reviewed-by: Jonathan Cameron Signed-off-by: Mark Brown --- drivers/iio/adc/Kconfig | 12 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/stm32-dfsdm-core.c | 309 ++++++++++++++++++++++++++++++++++++ drivers/iio/adc/stm32-dfsdm.h | 310 +++++++++++++++++++++++++++++++++++++ 4 files changed, 632 insertions(+) create mode 100644 drivers/iio/adc/stm32-dfsdm-core.c create mode 100644 drivers/iio/adc/stm32-dfsdm.h diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 5f9d04a8ba53..776192e68ad5 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -668,6 +668,18 @@ config STM32_ADC This driver can also be built as a module. If so, the module will be called stm32-adc. +config STM32_DFSDM_CORE + tristate "STMicroelectronics STM32 DFSDM core" + depends on (ARCH_STM32 && OF) || COMPILE_TEST + select REGMAP + select REGMAP_MMIO + help + Select this option to enable the driver for STMicroelectronics + STM32 digital filter for sigma delta converter. + + This driver can also be built as a module. If so, the module + will be called stm32-dfsdm-core. + config STX104 tristate "Apex Embedded Systems STX104 driver" depends on PC104 && X86 && ISA_BUS_API diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index fa5e7949f642..8dda348f1920 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_STX104) += stx104.o obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o obj-$(CONFIG_STM32_ADC) += stm32-adc.o +obj-$(CONFIG_STM32_DFSDM_CORE) += stm32-dfsdm-core.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o obj-$(CONFIG_TI_ADC084S021) += ti-adc084s021.o diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c new file mode 100644 index 000000000000..72427414db7f --- /dev/null +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -0,0 +1,309 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This file is part the core part STM32 DFSDM driver + * + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Arnaud Pouliquen for STMicroelectronics. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stm32-dfsdm.h" + +struct stm32_dfsdm_dev_data { + unsigned int num_filters; + unsigned int num_channels; + const struct regmap_config *regmap_cfg; +}; + +#define STM32H7_DFSDM_NUM_FILTERS 4 +#define STM32H7_DFSDM_NUM_CHANNELS 8 + +static bool stm32_dfsdm_volatile_reg(struct device *dev, unsigned int reg) +{ + if (reg < DFSDM_FILTER_BASE_ADR) + return false; + + /* + * Mask is done on register to avoid to list registers of all + * filter instances. + */ + switch (reg & DFSDM_FILTER_REG_MASK) { + case DFSDM_CR1(0) & DFSDM_FILTER_REG_MASK: + case DFSDM_ISR(0) & DFSDM_FILTER_REG_MASK: + case DFSDM_JDATAR(0) & DFSDM_FILTER_REG_MASK: + case DFSDM_RDATAR(0) & DFSDM_FILTER_REG_MASK: + return true; + } + + return false; +} + +static const struct regmap_config stm32h7_dfsdm_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = sizeof(u32), + .max_register = 0x2B8, + .volatile_reg = stm32_dfsdm_volatile_reg, + .fast_io = true, +}; + +static const struct stm32_dfsdm_dev_data stm32h7_dfsdm_data = { + .num_filters = STM32H7_DFSDM_NUM_FILTERS, + .num_channels = STM32H7_DFSDM_NUM_CHANNELS, + .regmap_cfg = &stm32h7_dfsdm_regmap_cfg, +}; + +struct dfsdm_priv { + struct platform_device *pdev; /* platform device */ + + struct stm32_dfsdm dfsdm; /* common data exported for all instances */ + + unsigned int spi_clk_out_div; /* SPI clkout divider value */ + atomic_t n_active_ch; /* number of current active channels */ + + struct clk *clk; /* DFSDM clock */ + struct clk *aclk; /* audio clock */ +}; + +/** + * stm32_dfsdm_start_dfsdm - start global dfsdm interface. + * + * Enable interface if n_active_ch is not null. + * @dfsdm: Handle used to retrieve dfsdm context. + */ +int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) +{ + struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm); + struct device *dev = &priv->pdev->dev; + unsigned int clk_div = priv->spi_clk_out_div; + int ret; + + if (atomic_inc_return(&priv->n_active_ch) == 1) { + ret = clk_prepare_enable(priv->clk); + if (ret < 0) { + dev_err(dev, "Failed to start clock\n"); + goto error_ret; + } + if (priv->aclk) { + ret = clk_prepare_enable(priv->aclk); + if (ret < 0) { + dev_err(dev, "Failed to start audio clock\n"); + goto disable_clk; + } + } + + /* Output the SPI CLKOUT (if clk_div == 0 clock if OFF) */ + ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), + DFSDM_CHCFGR1_CKOUTDIV_MASK, + DFSDM_CHCFGR1_CKOUTDIV(clk_div)); + if (ret < 0) + goto disable_aclk; + + /* Global enable of DFSDM interface */ + ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), + DFSDM_CHCFGR1_DFSDMEN_MASK, + DFSDM_CHCFGR1_DFSDMEN(1)); + if (ret < 0) + goto disable_aclk; + } + + dev_dbg(dev, "%s: n_active_ch %d\n", __func__, + atomic_read(&priv->n_active_ch)); + + return 0; + +disable_aclk: + clk_disable_unprepare(priv->aclk); +disable_clk: + clk_disable_unprepare(priv->clk); + +error_ret: + atomic_dec(&priv->n_active_ch); + + return ret; +} +EXPORT_SYMBOL_GPL(stm32_dfsdm_start_dfsdm); + +/** + * stm32_dfsdm_stop_dfsdm - stop global DFSDM interface. + * + * Disable interface if n_active_ch is null + * @dfsdm: Handle used to retrieve dfsdm context. + */ +int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm) +{ + struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm); + int ret; + + if (atomic_dec_and_test(&priv->n_active_ch)) { + /* Global disable of DFSDM interface */ + ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), + DFSDM_CHCFGR1_DFSDMEN_MASK, + DFSDM_CHCFGR1_DFSDMEN(0)); + if (ret < 0) + return ret; + + /* Stop SPI CLKOUT */ + ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), + DFSDM_CHCFGR1_CKOUTDIV_MASK, + DFSDM_CHCFGR1_CKOUTDIV(0)); + if (ret < 0) + return ret; + + clk_disable_unprepare(priv->clk); + if (priv->aclk) + clk_disable_unprepare(priv->aclk); + } + dev_dbg(&priv->pdev->dev, "%s: n_active_ch %d\n", __func__, + atomic_read(&priv->n_active_ch)); + + return 0; +} +EXPORT_SYMBOL_GPL(stm32_dfsdm_stop_dfsdm); + +static int stm32_dfsdm_parse_of(struct platform_device *pdev, + struct dfsdm_priv *priv) +{ + struct device_node *node = pdev->dev.of_node; + struct resource *res; + unsigned long clk_freq; + unsigned int spi_freq, rem; + int ret; + + if (!node) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Failed to get memory resource\n"); + return -ENODEV; + } + priv->dfsdm.phys_base = res->start; + priv->dfsdm.base = devm_ioremap_resource(&pdev->dev, res); + + /* + * "dfsdm" clock is mandatory for DFSDM peripheral clocking. + * "dfsdm" or "audio" clocks can be used as source clock for + * the SPI clock out signal and internal processing, depending + * on use case. + */ + priv->clk = devm_clk_get(&pdev->dev, "dfsdm"); + if (IS_ERR(priv->clk)) { + dev_err(&pdev->dev, "No stm32_dfsdm_clk clock found\n"); + return -EINVAL; + } + + priv->aclk = devm_clk_get(&pdev->dev, "audio"); + if (IS_ERR(priv->aclk)) + priv->aclk = NULL; + + if (priv->aclk) + clk_freq = clk_get_rate(priv->aclk); + else + clk_freq = clk_get_rate(priv->clk); + + /* SPI clock out frequency */ + ret = of_property_read_u32(pdev->dev.of_node, "spi-max-frequency", + &spi_freq); + if (ret < 0) { + /* No SPI master mode */ + return 0; + } + + priv->spi_clk_out_div = div_u64_rem(clk_freq, spi_freq, &rem) - 1; + priv->dfsdm.spi_master_freq = spi_freq; + + if (rem) { + dev_warn(&pdev->dev, "SPI clock not accurate\n"); + dev_warn(&pdev->dev, "%ld = %d * %d + %d\n", + clk_freq, spi_freq, priv->spi_clk_out_div + 1, rem); + } + + return 0; +}; + +static const struct of_device_id stm32_dfsdm_of_match[] = { + { + .compatible = "st,stm32h7-dfsdm", + .data = &stm32h7_dfsdm_data, + }, + {} +}; +MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match); + +static int stm32_dfsdm_probe(struct platform_device *pdev) +{ + struct dfsdm_priv *priv; + struct device_node *pnode = pdev->dev.of_node; + const struct of_device_id *of_id; + const struct stm32_dfsdm_dev_data *dev_data; + struct stm32_dfsdm *dfsdm; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->pdev = pdev; + + of_id = of_match_node(stm32_dfsdm_of_match, pnode); + if (!of_id->data) { + dev_err(&pdev->dev, "Data associated to device is missing\n"); + return -EINVAL; + } + + dev_data = (const struct stm32_dfsdm_dev_data *)of_id->data; + dfsdm = &priv->dfsdm; + dfsdm->fl_list = devm_kcalloc(&pdev->dev, dev_data->num_filters, + sizeof(*dfsdm->fl_list), GFP_KERNEL); + if (!dfsdm->fl_list) + return -ENOMEM; + + dfsdm->num_fls = dev_data->num_filters; + dfsdm->ch_list = devm_kcalloc(&pdev->dev, dev_data->num_channels, + sizeof(*dfsdm->ch_list), + GFP_KERNEL); + if (!dfsdm->ch_list) + return -ENOMEM; + dfsdm->num_chs = dev_data->num_channels; + + ret = stm32_dfsdm_parse_of(pdev, priv); + if (ret < 0) + return ret; + + dfsdm->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dfsdm", + dfsdm->base, + &stm32h7_dfsdm_regmap_cfg); + if (IS_ERR(dfsdm->regmap)) { + ret = PTR_ERR(dfsdm->regmap); + dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n", + __func__, ret); + return ret; + } + + platform_set_drvdata(pdev, dfsdm); + + return devm_of_platform_populate(&pdev->dev); +} + +static struct platform_driver stm32_dfsdm_driver = { + .probe = stm32_dfsdm_probe, + .driver = { + .name = "stm32-dfsdm", + .of_match_table = stm32_dfsdm_of_match, + }, +}; + +module_platform_driver(stm32_dfsdm_driver); + +MODULE_AUTHOR("Arnaud Pouliquen "); +MODULE_DESCRIPTION("STMicroelectronics STM32 dfsdm driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/stm32-dfsdm.h b/drivers/iio/adc/stm32-dfsdm.h new file mode 100644 index 000000000000..8708394b0725 --- /dev/null +++ b/drivers/iio/adc/stm32-dfsdm.h @@ -0,0 +1,310 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This file is part of STM32 DFSDM driver + * + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Arnaud Pouliquen . + */ + +#ifndef MDF_STM32_DFSDM__H +#define MDF_STM32_DFSDM__H + +#include + +/* + * STM32 DFSDM - global register map + * ________________________________________________________ + * | Offset | Registers block | + * -------------------------------------------------------- + * | 0x000 | CHANNEL 0 + COMMON CHANNEL FIELDS | + * -------------------------------------------------------- + * | 0x020 | CHANNEL 1 | + * -------------------------------------------------------- + * | ... | ..... | + * -------------------------------------------------------- + * | 0x0E0 | CHANNEL 7 | + * -------------------------------------------------------- + * | 0x100 | FILTER 0 + COMMON FILTER FIELDs | + * -------------------------------------------------------- + * | 0x200 | FILTER 1 | + * -------------------------------------------------------- + * | 0x300 | FILTER 2 | + * -------------------------------------------------------- + * | 0x400 | FILTER 3 | + * -------------------------------------------------------- + */ + +/* + * Channels register definitions + */ +#define DFSDM_CHCFGR1(y) ((y) * 0x20 + 0x00) +#define DFSDM_CHCFGR2(y) ((y) * 0x20 + 0x04) +#define DFSDM_AWSCDR(y) ((y) * 0x20 + 0x08) +#define DFSDM_CHWDATR(y) ((y) * 0x20 + 0x0C) +#define DFSDM_CHDATINR(y) ((y) * 0x20 + 0x10) + +/* CHCFGR1: Channel configuration register 1 */ +#define DFSDM_CHCFGR1_SITP_MASK GENMASK(1, 0) +#define DFSDM_CHCFGR1_SITP(v) FIELD_PREP(DFSDM_CHCFGR1_SITP_MASK, v) +#define DFSDM_CHCFGR1_SPICKSEL_MASK GENMASK(3, 2) +#define DFSDM_CHCFGR1_SPICKSEL(v) FIELD_PREP(DFSDM_CHCFGR1_SPICKSEL_MASK, v) +#define DFSDM_CHCFGR1_SCDEN_MASK BIT(5) +#define DFSDM_CHCFGR1_SCDEN(v) FIELD_PREP(DFSDM_CHCFGR1_SCDEN_MASK, v) +#define DFSDM_CHCFGR1_CKABEN_MASK BIT(6) +#define DFSDM_CHCFGR1_CKABEN(v) FIELD_PREP(DFSDM_CHCFGR1_CKABEN_MASK, v) +#define DFSDM_CHCFGR1_CHEN_MASK BIT(7) +#define DFSDM_CHCFGR1_CHEN(v) FIELD_PREP(DFSDM_CHCFGR1_CHEN_MASK, v) +#define DFSDM_CHCFGR1_CHINSEL_MASK BIT(8) +#define DFSDM_CHCFGR1_CHINSEL(v) FIELD_PREP(DFSDM_CHCFGR1_CHINSEL_MASK, v) +#define DFSDM_CHCFGR1_DATMPX_MASK GENMASK(13, 12) +#define DFSDM_CHCFGR1_DATMPX(v) FIELD_PREP(DFSDM_CHCFGR1_DATMPX_MASK, v) +#define DFSDM_CHCFGR1_DATPACK_MASK GENMASK(15, 14) +#define DFSDM_CHCFGR1_DATPACK(v) FIELD_PREP(DFSDM_CHCFGR1_DATPACK_MASK, v) +#define DFSDM_CHCFGR1_CKOUTDIV_MASK GENMASK(23, 16) +#define DFSDM_CHCFGR1_CKOUTDIV(v) FIELD_PREP(DFSDM_CHCFGR1_CKOUTDIV_MASK, v) +#define DFSDM_CHCFGR1_CKOUTSRC_MASK BIT(30) +#define DFSDM_CHCFGR1_CKOUTSRC(v) FIELD_PREP(DFSDM_CHCFGR1_CKOUTSRC_MASK, v) +#define DFSDM_CHCFGR1_DFSDMEN_MASK BIT(31) +#define DFSDM_CHCFGR1_DFSDMEN(v) FIELD_PREP(DFSDM_CHCFGR1_DFSDMEN_MASK, v) + +/* CHCFGR2: Channel configuration register 2 */ +#define DFSDM_CHCFGR2_DTRBS_MASK GENMASK(7, 3) +#define DFSDM_CHCFGR2_DTRBS(v) FIELD_PREP(DFSDM_CHCFGR2_DTRBS_MASK, v) +#define DFSDM_CHCFGR2_OFFSET_MASK GENMASK(31, 8) +#define DFSDM_CHCFGR2_OFFSET(v) FIELD_PREP(DFSDM_CHCFGR2_OFFSET_MASK, v) + +/* AWSCDR: Channel analog watchdog and short circuit detector */ +#define DFSDM_AWSCDR_SCDT_MASK GENMASK(7, 0) +#define DFSDM_AWSCDR_SCDT(v) FIELD_PREP(DFSDM_AWSCDR_SCDT_MASK, v) +#define DFSDM_AWSCDR_BKSCD_MASK GENMASK(15, 12) +#define DFSDM_AWSCDR_BKSCD(v) FIELD_PREP(DFSDM_AWSCDR_BKSCD_MASK, v) +#define DFSDM_AWSCDR_AWFOSR_MASK GENMASK(20, 16) +#define DFSDM_AWSCDR_AWFOSR(v) FIELD_PREP(DFSDM_AWSCDR_AWFOSR_MASK, v) +#define DFSDM_AWSCDR_AWFORD_MASK GENMASK(23, 22) +#define DFSDM_AWSCDR_AWFORD(v) FIELD_PREP(DFSDM_AWSCDR_AWFORD_MASK, v) + +/* + * Filters register definitions + */ +#define DFSDM_FILTER_BASE_ADR 0x100 +#define DFSDM_FILTER_REG_MASK 0x7F +#define DFSDM_FILTER_X_BASE_ADR(x) ((x) * 0x80 + DFSDM_FILTER_BASE_ADR) + +#define DFSDM_CR1(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x00) +#define DFSDM_CR2(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x04) +#define DFSDM_ISR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x08) +#define DFSDM_ICR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x0C) +#define DFSDM_JCHGR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x10) +#define DFSDM_FCR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x14) +#define DFSDM_JDATAR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x18) +#define DFSDM_RDATAR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x1C) +#define DFSDM_AWHTR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x20) +#define DFSDM_AWLTR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x24) +#define DFSDM_AWSR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x28) +#define DFSDM_AWCFR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x2C) +#define DFSDM_EXMAX(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x30) +#define DFSDM_EXMIN(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x34) +#define DFSDM_CNVTIMR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x38) + +/* CR1 Control register 1 */ +#define DFSDM_CR1_DFEN_MASK BIT(0) +#define DFSDM_CR1_DFEN(v) FIELD_PREP(DFSDM_CR1_DFEN_MASK, v) +#define DFSDM_CR1_JSWSTART_MASK BIT(1) +#define DFSDM_CR1_JSWSTART(v) FIELD_PREP(DFSDM_CR1_JSWSTART_MASK, v) +#define DFSDM_CR1_JSYNC_MASK BIT(3) +#define DFSDM_CR1_JSYNC(v) FIELD_PREP(DFSDM_CR1_JSYNC_MASK, v) +#define DFSDM_CR1_JSCAN_MASK BIT(4) +#define DFSDM_CR1_JSCAN(v) FIELD_PREP(DFSDM_CR1_JSCAN_MASK, v) +#define DFSDM_CR1_JDMAEN_MASK BIT(5) +#define DFSDM_CR1_JDMAEN(v) FIELD_PREP(DFSDM_CR1_JDMAEN_MASK, v) +#define DFSDM_CR1_JEXTSEL_MASK GENMASK(12, 8) +#define DFSDM_CR1_JEXTSEL(v) FIELD_PREP(DFSDM_CR1_JEXTSEL_MASK, v) +#define DFSDM_CR1_JEXTEN_MASK GENMASK(14, 13) +#define DFSDM_CR1_JEXTEN(v) FIELD_PREP(DFSDM_CR1_JEXTEN_MASK, v) +#define DFSDM_CR1_RSWSTART_MASK BIT(17) +#define DFSDM_CR1_RSWSTART(v) FIELD_PREP(DFSDM_CR1_RSWSTART_MASK, v) +#define DFSDM_CR1_RCONT_MASK BIT(18) +#define DFSDM_CR1_RCONT(v) FIELD_PREP(DFSDM_CR1_RCONT_MASK, v) +#define DFSDM_CR1_RSYNC_MASK BIT(19) +#define DFSDM_CR1_RSYNC(v) FIELD_PREP(DFSDM_CR1_RSYNC_MASK, v) +#define DFSDM_CR1_RDMAEN_MASK BIT(21) +#define DFSDM_CR1_RDMAEN(v) FIELD_PREP(DFSDM_CR1_RDMAEN_MASK, v) +#define DFSDM_CR1_RCH_MASK GENMASK(26, 24) +#define DFSDM_CR1_RCH(v) FIELD_PREP(DFSDM_CR1_RCH_MASK, v) +#define DFSDM_CR1_FAST_MASK BIT(29) +#define DFSDM_CR1_FAST(v) FIELD_PREP(DFSDM_CR1_FAST_MASK, v) +#define DFSDM_CR1_AWFSEL_MASK BIT(30) +#define DFSDM_CR1_AWFSEL(v) FIELD_PREP(DFSDM_CR1_AWFSEL_MASK, v) + +/* CR2: Control register 2 */ +#define DFSDM_CR2_IE_MASK GENMASK(6, 0) +#define DFSDM_CR2_IE(v) FIELD_PREP(DFSDM_CR2_IE_MASK, v) +#define DFSDM_CR2_JEOCIE_MASK BIT(0) +#define DFSDM_CR2_JEOCIE(v) FIELD_PREP(DFSDM_CR2_JEOCIE_MASK, v) +#define DFSDM_CR2_REOCIE_MASK BIT(1) +#define DFSDM_CR2_REOCIE(v) FIELD_PREP(DFSDM_CR2_REOCIE_MASK, v) +#define DFSDM_CR2_JOVRIE_MASK BIT(2) +#define DFSDM_CR2_JOVRIE(v) FIELD_PREP(DFSDM_CR2_JOVRIE_MASK, v) +#define DFSDM_CR2_ROVRIE_MASK BIT(3) +#define DFSDM_CR2_ROVRIE(v) FIELD_PREP(DFSDM_CR2_ROVRIE_MASK, v) +#define DFSDM_CR2_AWDIE_MASK BIT(4) +#define DFSDM_CR2_AWDIE(v) FIELD_PREP(DFSDM_CR2_AWDIE_MASK, v) +#define DFSDM_CR2_SCDIE_MASK BIT(5) +#define DFSDM_CR2_SCDIE(v) FIELD_PREP(DFSDM_CR2_SCDIE_MASK, v) +#define DFSDM_CR2_CKABIE_MASK BIT(6) +#define DFSDM_CR2_CKABIE(v) FIELD_PREP(DFSDM_CR2_CKABIE_MASK, v) +#define DFSDM_CR2_EXCH_MASK GENMASK(15, 8) +#define DFSDM_CR2_EXCH(v) FIELD_PREP(DFSDM_CR2_EXCH_MASK, v) +#define DFSDM_CR2_AWDCH_MASK GENMASK(23, 16) +#define DFSDM_CR2_AWDCH(v) FIELD_PREP(DFSDM_CR2_AWDCH_MASK, v) + +/* ISR: Interrupt status register */ +#define DFSDM_ISR_JEOCF_MASK BIT(0) +#define DFSDM_ISR_JEOCF(v) FIELD_PREP(DFSDM_ISR_JEOCF_MASK, v) +#define DFSDM_ISR_REOCF_MASK BIT(1) +#define DFSDM_ISR_REOCF(v) FIELD_PREP(DFSDM_ISR_REOCF_MASK, v) +#define DFSDM_ISR_JOVRF_MASK BIT(2) +#define DFSDM_ISR_JOVRF(v) FIELD_PREP(DFSDM_ISR_JOVRF_MASK, v) +#define DFSDM_ISR_ROVRF_MASK BIT(3) +#define DFSDM_ISR_ROVRF(v) FIELD_PREP(DFSDM_ISR_ROVRF_MASK, v) +#define DFSDM_ISR_AWDF_MASK BIT(4) +#define DFSDM_ISR_AWDF(v) FIELD_PREP(DFSDM_ISR_AWDF_MASK, v) +#define DFSDM_ISR_JCIP_MASK BIT(13) +#define DFSDM_ISR_JCIP(v) FIELD_PREP(DFSDM_ISR_JCIP_MASK, v) +#define DFSDM_ISR_RCIP_MASK BIT(14) +#define DFSDM_ISR_RCIP(v) FIELD_PREP(DFSDM_ISR_RCIP, v) +#define DFSDM_ISR_CKABF_MASK GENMASK(23, 16) +#define DFSDM_ISR_CKABF(v) FIELD_PREP(DFSDM_ISR_CKABF_MASK, v) +#define DFSDM_ISR_SCDF_MASK GENMASK(31, 24) +#define DFSDM_ISR_SCDF(v) FIELD_PREP(DFSDM_ISR_SCDF_MASK, v) + +/* ICR: Interrupt flag clear register */ +#define DFSDM_ICR_CLRJOVRF_MASK BIT(2) +#define DFSDM_ICR_CLRJOVRF(v) FIELD_PREP(DFSDM_ICR_CLRJOVRF_MASK, v) +#define DFSDM_ICR_CLRROVRF_MASK BIT(3) +#define DFSDM_ICR_CLRROVRF(v) FIELD_PREP(DFSDM_ICR_CLRROVRF_MASK, v) +#define DFSDM_ICR_CLRCKABF_MASK GENMASK(23, 16) +#define DFSDM_ICR_CLRCKABF(v) FIELD_PREP(DFSDM_ICR_CLRCKABF_MASK, v) +#define DFSDM_ICR_CLRCKABF_CH_MASK(y) BIT(16 + (y)) +#define DFSDM_ICR_CLRCKABF_CH(v, y) \ + (((v) << (16 + (y))) & DFSDM_ICR_CLRCKABF_CH_MASK(y)) +#define DFSDM_ICR_CLRSCDF_MASK GENMASK(31, 24) +#define DFSDM_ICR_CLRSCDF(v) FIELD_PREP(DFSDM_ICR_CLRSCDF_MASK, v) +#define DFSDM_ICR_CLRSCDF_CH_MASK(y) BIT(24 + (y)) +#define DFSDM_ICR_CLRSCDF_CH(v, y) \ + (((v) << (24 + (y))) & DFSDM_ICR_CLRSCDF_MASK(y)) + +/* FCR: Filter control register */ +#define DFSDM_FCR_IOSR_MASK GENMASK(7, 0) +#define DFSDM_FCR_IOSR(v) FIELD_PREP(DFSDM_FCR_IOSR_MASK, v) +#define DFSDM_FCR_FOSR_MASK GENMASK(25, 16) +#define DFSDM_FCR_FOSR(v) FIELD_PREP(DFSDM_FCR_FOSR_MASK, v) +#define DFSDM_FCR_FORD_MASK GENMASK(31, 29) +#define DFSDM_FCR_FORD(v) FIELD_PREP(DFSDM_FCR_FORD_MASK, v) + +/* RDATAR: Filter data register for regular channel */ +#define DFSDM_DATAR_CH_MASK GENMASK(2, 0) +#define DFSDM_DATAR_DATA_OFFSET 8 +#define DFSDM_DATAR_DATA_MASK GENMASK(31, DFSDM_DATAR_DATA_OFFSET) + +/* AWLTR: Filter analog watchdog low threshold register */ +#define DFSDM_AWLTR_BKAWL_MASK GENMASK(3, 0) +#define DFSDM_AWLTR_BKAWL(v) FIELD_PREP(DFSDM_AWLTR_BKAWL_MASK, v) +#define DFSDM_AWLTR_AWLT_MASK GENMASK(31, 8) +#define DFSDM_AWLTR_AWLT(v) FIELD_PREP(DFSDM_AWLTR_AWLT_MASK, v) + +/* AWHTR: Filter analog watchdog low threshold register */ +#define DFSDM_AWHTR_BKAWH_MASK GENMASK(3, 0) +#define DFSDM_AWHTR_BKAWH(v) FIELD_PREP(DFSDM_AWHTR_BKAWH_MASK, v) +#define DFSDM_AWHTR_AWHT_MASK GENMASK(31, 8) +#define DFSDM_AWHTR_AWHT(v) FIELD_PREP(DFSDM_AWHTR_AWHT_MASK, v) + +/* AWSR: Filter watchdog status register */ +#define DFSDM_AWSR_AWLTF_MASK GENMASK(7, 0) +#define DFSDM_AWSR_AWLTF(v) FIELD_PREP(DFSDM_AWSR_AWLTF_MASK, v) +#define DFSDM_AWSR_AWHTF_MASK GENMASK(15, 8) +#define DFSDM_AWSR_AWHTF(v) FIELD_PREP(DFSDM_AWSR_AWHTF_MASK, v) + +/* AWCFR: Filter watchdog status register */ +#define DFSDM_AWCFR_AWLTF_MASK GENMASK(7, 0) +#define DFSDM_AWCFR_AWLTF(v) FIELD_PREP(DFSDM_AWCFR_AWLTF_MASK, v) +#define DFSDM_AWCFR_AWHTF_MASK GENMASK(15, 8) +#define DFSDM_AWCFR_AWHTF(v) FIELD_PREP(DFSDM_AWCFR_AWHTF_MASK, v) + +/* DFSDM filter order */ +enum stm32_dfsdm_sinc_order { + DFSDM_FASTSINC_ORDER, /* FastSinc filter type */ + DFSDM_SINC1_ORDER, /* Sinc 1 filter type */ + DFSDM_SINC2_ORDER, /* Sinc 2 filter type */ + DFSDM_SINC3_ORDER, /* Sinc 3 filter type */ + DFSDM_SINC4_ORDER, /* Sinc 4 filter type (N.A. for watchdog) */ + DFSDM_SINC5_ORDER, /* Sinc 5 filter type (N.A. for watchdog) */ + DFSDM_NB_SINC_ORDER, +}; + +/** + * struct stm32_dfsdm_filter - structure relative to stm32 FDSDM filter + * @iosr: integrator oversampling + * @fosr: filter oversampling + * @ford: filter order + * @res: output sample resolution + * @sync_mode: filter synchronized with filter 0 + * @fast: filter fast mode + */ +struct stm32_dfsdm_filter { + unsigned int iosr; + unsigned int fosr; + enum stm32_dfsdm_sinc_order ford; + u64 res; + unsigned int sync_mode; + unsigned int fast; +}; + +/** + * struct stm32_dfsdm_channel - structure relative to stm32 FDSDM channel + * @id: id of the channel + * @type: interface type linked to stm32_dfsdm_chan_type + * @src: interface type linked to stm32_dfsdm_chan_src + * @alt_si: alternative serial input interface + */ +struct stm32_dfsdm_channel { + unsigned int id; + unsigned int type; + unsigned int src; + unsigned int alt_si; +}; + +/** + * struct stm32_dfsdm - stm32 FDSDM driver common data (for all instances) + * @base: control registers base cpu addr + * @phys_base: DFSDM IP register physical address + * @regmap: regmap for register read/write + * @fl_list: filter resources list + * @num_fls: number of filter resources available + * @ch_list: channel resources list + * @num_chs: number of channel resources available + * @spi_master_freq: SPI clock out frequency + */ +struct stm32_dfsdm { + void __iomem *base; + phys_addr_t phys_base; + struct regmap *regmap; + struct stm32_dfsdm_filter *fl_list; + unsigned int num_fls; + struct stm32_dfsdm_channel *ch_list; + unsigned int num_chs; + unsigned int spi_master_freq; +}; + +/* DFSDM channel serial spi clock source */ +enum stm32_dfsdm_spi_clk_src { + DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL, + DFSDM_CHANNEL_SPI_CLOCK_INTERNAL, + DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING, + DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING +}; + +int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm); +int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm); + +#endif -- cgit v1.2.3 From e2e6771c646251657fafb2a78db566d5c2c70635 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Wed, 10 Jan 2018 11:13:11 +0100 Subject: IIO: ADC: add STM32 DFSDM sigma delta ADC support Add DFSDM driver to handle sigma delta ADC. Signed-off-by: Arnaud Pouliquen Reviewed-by: Jonathan Cameron Signed-off-by: Mark Brown --- drivers/iio/adc/Kconfig | 13 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/stm32-dfsdm-adc.c | 728 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 742 insertions(+) create mode 100644 drivers/iio/adc/stm32-dfsdm-adc.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 776192e68ad5..39e3b345a6c8 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -680,6 +680,19 @@ config STM32_DFSDM_CORE This driver can also be built as a module. If so, the module will be called stm32-dfsdm-core. +config STM32_DFSDM_ADC + tristate "STMicroelectronics STM32 dfsdm adc" + depends on (ARCH_STM32 && OF) || COMPILE_TEST + select STM32_DFSDM_CORE + select REGMAP_MMIO + select IIO_BUFFER_HW_CONSUMER + help + Select this option to support ADCSigma delta modulator for + STMicroelectronics STM32 digital filter for sigma delta converter. + + This driver can also be built as a module. If so, the module + will be called stm32-dfsdm-adc. + config STX104 tristate "Apex Embedded Systems STX104 driver" depends on PC104 && X86 && ISA_BUS_API diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 8dda348f1920..28a9423997f3 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o obj-$(CONFIG_STM32_ADC) += stm32-adc.o obj-$(CONFIG_STM32_DFSDM_CORE) += stm32-dfsdm-core.o +obj-$(CONFIG_STM32_DFSDM_ADC) += stm32-dfsdm-adc.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o obj-$(CONFIG_TI_ADC084S021) += ti-adc084s021.o diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c new file mode 100644 index 000000000000..68b5920e92cb --- /dev/null +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -0,0 +1,728 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This file is the ADC part of the STM32 DFSDM driver + * + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author: Arnaud Pouliquen . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stm32-dfsdm.h" + +/* Conversion timeout */ +#define DFSDM_TIMEOUT_US 100000 +#define DFSDM_TIMEOUT (msecs_to_jiffies(DFSDM_TIMEOUT_US / 1000)) + +/* Oversampling attribute default */ +#define DFSDM_DEFAULT_OVERSAMPLING 100 + +/* Oversampling max values */ +#define DFSDM_MAX_INT_OVERSAMPLING 256 +#define DFSDM_MAX_FL_OVERSAMPLING 1024 + +/* Max sample resolutions */ +#define DFSDM_MAX_RES BIT(31) +#define DFSDM_DATA_RES BIT(23) + +enum sd_converter_type { + DFSDM_AUDIO, + DFSDM_IIO, +}; + +struct stm32_dfsdm_dev_data { + int type; + int (*init)(struct iio_dev *indio_dev); + unsigned int num_channels; + const struct regmap_config *regmap_cfg; +}; + +struct stm32_dfsdm_adc { + struct stm32_dfsdm *dfsdm; + const struct stm32_dfsdm_dev_data *dev_data; + unsigned int fl_id; + unsigned int ch_id; + + /* ADC specific */ + unsigned int oversamp; + struct iio_hw_consumer *hwc; + struct completion completion; + u32 *buffer; + +}; + +struct stm32_dfsdm_str2field { + const char *name; + unsigned int val; +}; + +/* DFSDM channel serial interface type */ +static const struct stm32_dfsdm_str2field stm32_dfsdm_chan_type[] = { + { "SPI_R", 0 }, /* SPI with data on rising edge */ + { "SPI_F", 1 }, /* SPI with data on falling edge */ + { "MANCH_R", 2 }, /* Manchester codec, rising edge = logic 0 */ + { "MANCH_F", 3 }, /* Manchester codec, falling edge = logic 1 */ + {}, +}; + +/* DFSDM channel clock source */ +static const struct stm32_dfsdm_str2field stm32_dfsdm_chan_src[] = { + /* External SPI clock (CLKIN x) */ + { "CLKIN", DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL }, + /* Internal SPI clock (CLKOUT) */ + { "CLKOUT", DFSDM_CHANNEL_SPI_CLOCK_INTERNAL }, + /* Internal SPI clock divided by 2 (falling edge) */ + { "CLKOUT_F", DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING }, + /* Internal SPI clock divided by 2 (falling edge) */ + { "CLKOUT_R", DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING }, + {}, +}; + +static int stm32_dfsdm_str2val(const char *str, + const struct stm32_dfsdm_str2field *list) +{ + const struct stm32_dfsdm_str2field *p = list; + + for (p = list; p && p->name; p++) + if (!strcmp(p->name, str)) + return p->val; + + return -EINVAL; +} + +static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, + unsigned int fast, unsigned int oversamp) +{ + unsigned int i, d, fosr, iosr; + u64 res; + s64 delta; + unsigned int m = 1; /* multiplication factor */ + unsigned int p = fl->ford; /* filter order (ford) */ + + pr_debug("%s: Requested oversampling: %d\n", __func__, oversamp); + /* + * This function tries to compute filter oversampling and integrator + * oversampling, base on oversampling ratio requested by user. + * + * Decimation d depends on the filter order and the oversampling ratios. + * ford: filter order + * fosr: filter over sampling ratio + * iosr: integrator over sampling ratio + */ + if (fl->ford == DFSDM_FASTSINC_ORDER) { + m = 2; + p = 2; + } + + /* + * Look for filter and integrator oversampling ratios which allows + * to reach 24 bits data output resolution. + * Leave as soon as if exact resolution if reached. + * Otherwise the higher resolution below 32 bits is kept. + */ + for (fosr = 1; fosr <= DFSDM_MAX_FL_OVERSAMPLING; fosr++) { + for (iosr = 1; iosr <= DFSDM_MAX_INT_OVERSAMPLING; iosr++) { + if (fast) + d = fosr * iosr; + else if (fl->ford == DFSDM_FASTSINC_ORDER) + d = fosr * (iosr + 3) + 2; + else + d = fosr * (iosr - 1 + p) + p; + + if (d > oversamp) + break; + else if (d != oversamp) + continue; + /* + * Check resolution (limited to signed 32 bits) + * res <= 2^31 + * Sincx filters: + * res = m * fosr^p x iosr (with m=1, p=ford) + * FastSinc filter + * res = m * fosr^p x iosr (with m=2, p=2) + */ + res = fosr; + for (i = p - 1; i > 0; i--) { + res = res * (u64)fosr; + if (res > DFSDM_MAX_RES) + break; + } + if (res > DFSDM_MAX_RES) + continue; + res = res * (u64)m * (u64)iosr; + if (res > DFSDM_MAX_RES) + continue; + + delta = res - DFSDM_DATA_RES; + + if (res >= fl->res) { + fl->res = res; + fl->fosr = fosr; + fl->iosr = iosr; + fl->fast = fast; + pr_debug("%s: fosr = %d, iosr = %d\n", + __func__, fl->fosr, fl->iosr); + } + + if (!delta) + return 0; + } + } + + if (!fl->fosr) + return -EINVAL; + + return 0; +} + +static int stm32_dfsdm_start_channel(struct stm32_dfsdm *dfsdm, + unsigned int ch_id) +{ + return regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(ch_id), + DFSDM_CHCFGR1_CHEN_MASK, + DFSDM_CHCFGR1_CHEN(1)); +} + +static void stm32_dfsdm_stop_channel(struct stm32_dfsdm *dfsdm, + unsigned int ch_id) +{ + regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(ch_id), + DFSDM_CHCFGR1_CHEN_MASK, DFSDM_CHCFGR1_CHEN(0)); +} + +static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm, + struct stm32_dfsdm_channel *ch) +{ + unsigned int id = ch->id; + struct regmap *regmap = dfsdm->regmap; + int ret; + + ret = regmap_update_bits(regmap, DFSDM_CHCFGR1(id), + DFSDM_CHCFGR1_SITP_MASK, + DFSDM_CHCFGR1_SITP(ch->type)); + if (ret < 0) + return ret; + ret = regmap_update_bits(regmap, DFSDM_CHCFGR1(id), + DFSDM_CHCFGR1_SPICKSEL_MASK, + DFSDM_CHCFGR1_SPICKSEL(ch->src)); + if (ret < 0) + return ret; + return regmap_update_bits(regmap, DFSDM_CHCFGR1(id), + DFSDM_CHCFGR1_CHINSEL_MASK, + DFSDM_CHCFGR1_CHINSEL(ch->alt_si)); +} + +static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm, + unsigned int fl_id) +{ + int ret; + + /* Enable filter */ + ret = regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id), + DFSDM_CR1_DFEN_MASK, DFSDM_CR1_DFEN(1)); + if (ret < 0) + return ret; + + /* Start conversion */ + return regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id), + DFSDM_CR1_RSWSTART_MASK, + DFSDM_CR1_RSWSTART(1)); +} + +void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, unsigned int fl_id) +{ + /* Disable conversion */ + regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id), + DFSDM_CR1_DFEN_MASK, DFSDM_CR1_DFEN(0)); +} + +static int stm32_dfsdm_filter_configure(struct stm32_dfsdm *dfsdm, + unsigned int fl_id, unsigned int ch_id) +{ + struct regmap *regmap = dfsdm->regmap; + struct stm32_dfsdm_filter *fl = &dfsdm->fl_list[fl_id]; + int ret; + + /* Average integrator oversampling */ + ret = regmap_update_bits(regmap, DFSDM_FCR(fl_id), DFSDM_FCR_IOSR_MASK, + DFSDM_FCR_IOSR(fl->iosr - 1)); + if (ret) + return ret; + + /* Filter order and Oversampling */ + ret = regmap_update_bits(regmap, DFSDM_FCR(fl_id), DFSDM_FCR_FOSR_MASK, + DFSDM_FCR_FOSR(fl->fosr - 1)); + if (ret) + return ret; + + ret = regmap_update_bits(regmap, DFSDM_FCR(fl_id), DFSDM_FCR_FORD_MASK, + DFSDM_FCR_FORD(fl->ford)); + if (ret) + return ret; + + /* No scan mode supported for the moment */ + ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id), DFSDM_CR1_RCH_MASK, + DFSDM_CR1_RCH(ch_id)); + if (ret) + return ret; + + return regmap_update_bits(regmap, DFSDM_CR1(fl_id), + DFSDM_CR1_RSYNC_MASK, + DFSDM_CR1_RSYNC(fl->sync_mode)); +} + +int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, + struct iio_dev *indio_dev, + struct iio_chan_spec *ch) +{ + struct stm32_dfsdm_channel *df_ch; + const char *of_str; + int chan_idx = ch->scan_index; + int ret, val; + + ret = of_property_read_u32_index(indio_dev->dev.of_node, + "st,adc-channels", chan_idx, + &ch->channel); + if (ret < 0) { + dev_err(&indio_dev->dev, + " Error parsing 'st,adc-channels' for idx %d\n", + chan_idx); + return ret; + } + if (ch->channel >= dfsdm->num_chs) { + dev_err(&indio_dev->dev, + " Error bad channel number %d (max = %d)\n", + ch->channel, dfsdm->num_chs); + return -EINVAL; + } + + ret = of_property_read_string_index(indio_dev->dev.of_node, + "st,adc-channel-names", chan_idx, + &ch->datasheet_name); + if (ret < 0) { + dev_err(&indio_dev->dev, + " Error parsing 'st,adc-channel-names' for idx %d\n", + chan_idx); + return ret; + } + + df_ch = &dfsdm->ch_list[ch->channel]; + df_ch->id = ch->channel; + + ret = of_property_read_string_index(indio_dev->dev.of_node, + "st,adc-channel-types", chan_idx, + &of_str); + if (!ret) { + val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_type); + if (val < 0) + return val; + } else { + val = 0; + } + df_ch->type = val; + + ret = of_property_read_string_index(indio_dev->dev.of_node, + "st,adc-channel-clk-src", chan_idx, + &of_str); + if (!ret) { + val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_src); + if (val < 0) + return val; + } else { + val = 0; + } + df_ch->src = val; + + ret = of_property_read_u32_index(indio_dev->dev.of_node, + "st,adc-alt-channel", chan_idx, + &df_ch->alt_si); + if (ret < 0) + df_ch->alt_si = 0; + + return 0; +} + +static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc, bool dma) +{ + struct regmap *regmap = adc->dfsdm->regmap; + int ret; + + ret = stm32_dfsdm_start_channel(adc->dfsdm, adc->ch_id); + if (ret < 0) + return ret; + + ret = stm32_dfsdm_filter_configure(adc->dfsdm, adc->fl_id, + adc->ch_id); + if (ret < 0) + goto stop_channels; + + ret = stm32_dfsdm_start_filter(adc->dfsdm, adc->fl_id); + if (ret < 0) + goto stop_channels; + + return 0; + +stop_channels: + regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), + DFSDM_CR1_RDMAEN_MASK, 0); + + regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), + DFSDM_CR1_RCONT_MASK, 0); + stm32_dfsdm_stop_channel(adc->dfsdm, adc->fl_id); + + return ret; +} + +static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc) +{ + struct regmap *regmap = adc->dfsdm->regmap; + + stm32_dfsdm_stop_filter(adc->dfsdm, adc->fl_id); + + /* Clean conversion options */ + regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), + DFSDM_CR1_RDMAEN_MASK, 0); + + regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), + DFSDM_CR1_RCONT_MASK, 0); + + stm32_dfsdm_stop_channel(adc->dfsdm, adc->ch_id); +} + +static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *res) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + long timeout; + int ret; + + reinit_completion(&adc->completion); + + adc->buffer = res; + + ret = stm32_dfsdm_start_dfsdm(adc->dfsdm); + if (ret < 0) + return ret; + + ret = regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id), + DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(1)); + if (ret < 0) + goto stop_dfsdm; + + ret = stm32_dfsdm_start_conv(adc, false); + if (ret < 0) { + regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id), + DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0)); + goto stop_dfsdm; + } + + timeout = wait_for_completion_interruptible_timeout(&adc->completion, + DFSDM_TIMEOUT); + + /* Mask IRQ for regular conversion achievement*/ + regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id), + DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0)); + + if (timeout == 0) + ret = -ETIMEDOUT; + else if (timeout < 0) + ret = timeout; + else + ret = IIO_VAL_INT; + + stm32_dfsdm_stop_conv(adc); + +stop_dfsdm: + stm32_dfsdm_stop_dfsdm(adc->dfsdm); + + return ret; +} + +static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; + int ret = -EINVAL; + + if (mask == IIO_CHAN_INFO_OVERSAMPLING_RATIO) { + ret = stm32_dfsdm_set_osrs(fl, 0, val); + if (!ret) + adc->oversamp = val; + } + + return ret; +} + +static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = iio_hw_consumer_enable(adc->hwc); + if (ret < 0) { + dev_err(&indio_dev->dev, + "%s: IIO enable failed (channel %d)\n", + __func__, chan->channel); + return ret; + } + ret = stm32_dfsdm_single_conv(indio_dev, chan, val); + iio_hw_consumer_disable(adc->hwc); + if (ret < 0) { + dev_err(&indio_dev->dev, + "%s: Conversion failed (channel %d)\n", + __func__, chan->channel); + return ret; + } + return IIO_VAL_INT; + + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = adc->oversamp; + + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static const struct iio_info stm32_dfsdm_info_adc = { + .read_raw = stm32_dfsdm_read_raw, + .write_raw = stm32_dfsdm_write_raw, +}; + +static irqreturn_t stm32_dfsdm_irq(int irq, void *arg) +{ + struct stm32_dfsdm_adc *adc = arg; + struct iio_dev *indio_dev = iio_priv_to_dev(adc); + struct regmap *regmap = adc->dfsdm->regmap; + unsigned int status, int_en; + + regmap_read(regmap, DFSDM_ISR(adc->fl_id), &status); + regmap_read(regmap, DFSDM_CR2(adc->fl_id), &int_en); + + if (status & DFSDM_ISR_REOCF_MASK) { + /* Read the data register clean the IRQ status */ + regmap_read(regmap, DFSDM_RDATAR(adc->fl_id), adc->buffer); + complete(&adc->completion); + } + + if (status & DFSDM_ISR_ROVRF_MASK) { + if (int_en & DFSDM_CR2_ROVRIE_MASK) + dev_warn(&indio_dev->dev, "Overrun detected\n"); + regmap_update_bits(regmap, DFSDM_ICR(adc->fl_id), + DFSDM_ICR_CLRROVRF_MASK, + DFSDM_ICR_CLRROVRF_MASK); + } + + return IRQ_HANDLED; +} + +static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, + struct iio_chan_spec *ch) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + int ret; + + ret = stm32_dfsdm_channel_parse_of(adc->dfsdm, indio_dev, ch); + if (ret < 0) + return ret; + + ch->type = IIO_VOLTAGE; + ch->indexed = 1; + + /* + * IIO_CHAN_INFO_RAW: used to compute regular conversion + * IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling + */ + ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); + ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); + + ch->scan_type.sign = 'u'; + ch->scan_type.realbits = 24; + ch->scan_type.storagebits = 32; + adc->ch_id = ch->channel; + + return stm32_dfsdm_chan_configure(adc->dfsdm, + &adc->dfsdm->ch_list[ch->channel]); +} + +static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) +{ + struct iio_chan_spec *ch; + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + int num_ch; + int ret, chan_idx; + + adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING; + ret = stm32_dfsdm_set_osrs(&adc->dfsdm->fl_list[adc->fl_id], 0, + adc->oversamp); + if (ret < 0) + return ret; + + num_ch = of_property_count_u32_elems(indio_dev->dev.of_node, + "st,adc-channels"); + if (num_ch < 0 || num_ch > adc->dfsdm->num_chs) { + dev_err(&indio_dev->dev, "Bad st,adc-channels\n"); + return num_ch < 0 ? num_ch : -EINVAL; + } + + /* Bind to SD modulator IIO device */ + adc->hwc = devm_iio_hw_consumer_alloc(&indio_dev->dev); + if (IS_ERR(adc->hwc)) + return -EPROBE_DEFER; + + ch = devm_kcalloc(&indio_dev->dev, num_ch, sizeof(*ch), + GFP_KERNEL); + if (!ch) + return -ENOMEM; + + for (chan_idx = 0; chan_idx < num_ch; chan_idx++) { + ch->scan_index = chan_idx; + ret = stm32_dfsdm_adc_chan_init_one(indio_dev, ch); + if (ret < 0) { + dev_err(&indio_dev->dev, "Channels init failed\n"); + return ret; + } + } + + indio_dev->num_channels = num_ch; + indio_dev->channels = ch; + + init_completion(&adc->completion); + + return 0; +} + +static const struct stm32_dfsdm_dev_data stm32h7_dfsdm_adc_data = { + .type = DFSDM_IIO, + .init = stm32_dfsdm_adc_init, +}; + +static const struct of_device_id stm32_dfsdm_adc_match[] = { + { + .compatible = "st,stm32-dfsdm-adc", + .data = &stm32h7_dfsdm_adc_data, + }, + {} +}; + +static int stm32_dfsdm_adc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct stm32_dfsdm_adc *adc; + struct device_node *np = dev->of_node; + const struct stm32_dfsdm_dev_data *dev_data; + struct iio_dev *iio; + const struct of_device_id *of_id; + char *name; + int ret, irq, val; + + of_id = of_match_node(stm32_dfsdm_adc_match, np); + if (!of_id->data) { + dev_err(&pdev->dev, "Data associated to device is missing\n"); + return -EINVAL; + } + + dev_data = (const struct stm32_dfsdm_dev_data *)of_id->data; + + iio = devm_iio_device_alloc(dev, sizeof(*adc)); + if (IS_ERR(iio)) { + dev_err(dev, "%s: Failed to allocate IIO\n", __func__); + return PTR_ERR(iio); + } + + adc = iio_priv(iio); + if (IS_ERR(adc)) { + dev_err(dev, "%s: Failed to allocate ADC\n", __func__); + return PTR_ERR(adc); + } + adc->dfsdm = dev_get_drvdata(dev->parent); + + iio->dev.parent = dev; + iio->dev.of_node = np; + iio->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; + + platform_set_drvdata(pdev, adc); + + ret = of_property_read_u32(dev->of_node, "reg", &adc->fl_id); + if (ret != 0) { + dev_err(dev, "Missing reg property\n"); + return -EINVAL; + } + + name = devm_kzalloc(dev, sizeof("dfsdm-adc0"), GFP_KERNEL); + if (!name) + return -ENOMEM; + iio->info = &stm32_dfsdm_info_adc; + snprintf(name, sizeof("dfsdm-adc0"), "dfsdm-adc%d", adc->fl_id); + iio->name = name; + + /* + * In a first step IRQs generated for channels are not treated. + * So IRQ associated to filter instance 0 is dedicated to the Filter 0. + */ + irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(dev, irq, stm32_dfsdm_irq, + 0, pdev->name, adc); + if (ret < 0) { + dev_err(dev, "Failed to request IRQ\n"); + return ret; + } + + ret = of_property_read_u32(dev->of_node, "st,filter-order", &val); + if (ret < 0) { + dev_err(dev, "Failed to set filter order\n"); + return ret; + } + + adc->dfsdm->fl_list[adc->fl_id].ford = val; + + ret = of_property_read_u32(dev->of_node, "st,filter0-sync", &val); + if (!ret) + adc->dfsdm->fl_list[adc->fl_id].sync_mode = val; + + adc->dev_data = dev_data; + ret = dev_data->init(iio); + if (ret < 0) + return ret; + + return iio_device_register(iio); +} + +static int stm32_dfsdm_adc_remove(struct platform_device *pdev) +{ + struct stm32_dfsdm_adc *adc = platform_get_drvdata(pdev); + struct iio_dev *indio_dev = iio_priv_to_dev(adc); + + iio_device_unregister(indio_dev); + + return 0; +} + +static struct platform_driver stm32_dfsdm_adc_driver = { + .driver = { + .name = "stm32-dfsdm-adc", + .of_match_table = stm32_dfsdm_adc_match, + }, + .probe = stm32_dfsdm_adc_probe, + .remove = stm32_dfsdm_adc_remove, +}; +module_platform_driver(stm32_dfsdm_adc_driver); + +MODULE_DESCRIPTION("STM32 sigma delta ADC"); +MODULE_AUTHOR("Arnaud Pouliquen "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From eca949800d2dd761bc0c73b793e4e9ad4a997469 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Wed, 10 Jan 2018 11:13:12 +0100 Subject: IIO: ADC: add stm32 DFSDM support for PDM microphone This code offers a way to handle PDM audio microphones in ASOC framework. Audio driver should use consumer API. A specific management is implemented for DMA, with a callback, to allows to handle audio buffers efficiently. Signed-off-by: Arnaud Pouliquen Reviewed-by: Jonathan Cameron Signed-off-by: Mark Brown --- .../ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 | 16 + drivers/iio/adc/stm32-dfsdm-adc.c | 502 ++++++++++++++++++++- include/linux/iio/adc/stm32-dfsdm-adc.h | 18 + 3 files changed, 529 insertions(+), 7 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 create mode 100644 include/linux/iio/adc/stm32-dfsdm-adc.h diff --git a/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 b/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 new file mode 100644 index 000000000000..da9822309f07 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 @@ -0,0 +1,16 @@ +What: /sys/bus/iio/devices/iio:deviceX/in_voltage_spi_clk_freq +KernelVersion: 4.14 +Contact: arnaud.pouliquen@st.com +Description: + For audio purpose only. + Used by audio driver to set/get the spi input frequency. + This is mandatory if DFSDM is slave on SPI bus, to + provide information on the SPI clock frequency during runtime + Notice that the SPI frequency should be a multiple of sample + frequency to ensure the precision. + if DFSDM input is SPI master + Reading SPI clkout frequency, + error on writing + If DFSDM input is SPI Slave: + Reading returns value previously set. + Writing value before starting conversions. \ No newline at end of file diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 68b5920e92cb..b03ca3f94331 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -6,19 +6,23 @@ * Author: Arnaud Pouliquen . */ +#include +#include #include #include #include #include #include #include -#include +#include #include #include #include #include "stm32-dfsdm.h" +#define DFSDM_DMA_BUFFER_SIZE (4 * PAGE_SIZE) + /* Conversion timeout */ #define DFSDM_TIMEOUT_US 100000 #define DFSDM_TIMEOUT (msecs_to_jiffies(DFSDM_TIMEOUT_US / 1000)) @@ -58,6 +62,18 @@ struct stm32_dfsdm_adc { struct completion completion; u32 *buffer; + /* Audio specific */ + unsigned int spi_freq; /* SPI bus clock frequency */ + unsigned int sample_freq; /* Sample frequency after filter decimation */ + int (*cb)(const void *data, size_t size, void *cb_priv); + void *cb_priv; + + /* DMA */ + u8 *rx_buf; + unsigned int bufi; /* Buffer current position */ + unsigned int buf_sz; /* Buffer size */ + struct dma_chan *dma_chan; + dma_addr_t dma_buf; }; struct stm32_dfsdm_str2field { @@ -351,10 +367,63 @@ int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, return 0; } +static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev, + uintptr_t priv, + const struct iio_chan_spec *chan, + char *buf) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", adc->spi_freq); +} + +static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, + uintptr_t priv, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; + struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[adc->ch_id]; + unsigned int sample_freq = adc->sample_freq; + unsigned int spi_freq; + int ret; + + dev_err(&indio_dev->dev, "enter %s\n", __func__); + /* If DFSDM is master on SPI, SPI freq can not be updated */ + if (ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL) + return -EPERM; + + ret = kstrtoint(buf, 0, &spi_freq); + if (ret) + return ret; + + if (!spi_freq) + return -EINVAL; + + if (sample_freq) { + if (spi_freq % sample_freq) + dev_warn(&indio_dev->dev, + "Sampling rate not accurate (%d)\n", + spi_freq / (spi_freq / sample_freq)); + + ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / sample_freq)); + if (ret < 0) { + dev_err(&indio_dev->dev, + "No filter parameters that match!\n"); + return ret; + } + } + adc->spi_freq = spi_freq; + + return len; +} + static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc, bool dma) { struct regmap *regmap = adc->dfsdm->regmap; int ret; + unsigned int dma_en = 0, cont_en = 0; ret = stm32_dfsdm_start_channel(adc->dfsdm, adc->ch_id); if (ret < 0) @@ -365,6 +434,24 @@ static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc, bool dma) if (ret < 0) goto stop_channels; + if (dma) { + /* Enable DMA transfer*/ + dma_en = DFSDM_CR1_RDMAEN(1); + /* Enable conversion triggered by SPI clock*/ + cont_en = DFSDM_CR1_RCONT(1); + } + /* Enable DMA transfer*/ + ret = regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), + DFSDM_CR1_RDMAEN_MASK, dma_en); + if (ret < 0) + goto stop_channels; + + /* Enable conversion triggered by SPI clock*/ + ret = regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), + DFSDM_CR1_RCONT_MASK, cont_en); + if (ret < 0) + goto stop_channels; + ret = stm32_dfsdm_start_filter(adc->dfsdm, adc->fl_id); if (ret < 0) goto stop_channels; @@ -398,6 +485,231 @@ static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc) stm32_dfsdm_stop_channel(adc->dfsdm, adc->ch_id); } +static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, + unsigned int val) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + unsigned int watermark = DFSDM_DMA_BUFFER_SIZE / 2; + + /* + * DMA cyclic transfers are used, buffer is split into two periods. + * There should be : + * - always one buffer (period) DMA is working on + * - one buffer (period) driver pushed to ASoC side. + */ + watermark = min(watermark, val * (unsigned int)(sizeof(u32))); + adc->buf_sz = watermark * 2; + + return 0; +} + +static unsigned int stm32_dfsdm_adc_dma_residue(struct stm32_dfsdm_adc *adc) +{ + struct dma_tx_state state; + enum dma_status status; + + status = dmaengine_tx_status(adc->dma_chan, + adc->dma_chan->cookie, + &state); + if (status == DMA_IN_PROGRESS) { + /* Residue is size in bytes from end of buffer */ + unsigned int i = adc->buf_sz - state.residue; + unsigned int size; + + /* Return available bytes */ + if (i >= adc->bufi) + size = i - adc->bufi; + else + size = adc->buf_sz + i - adc->bufi; + + return size; + } + + return 0; +} + +static void stm32_dfsdm_audio_dma_buffer_done(void *data) +{ + struct iio_dev *indio_dev = data; + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + int available = stm32_dfsdm_adc_dma_residue(adc); + size_t old_pos; + + /* + * FIXME: In Kernel interface does not support cyclic DMA buffer,and + * offers only an interface to push data samples per samples. + * For this reason IIO buffer interface is not used and interface is + * bypassed using a private callback registered by ASoC. + * This should be a temporary solution waiting a cyclic DMA engine + * support in IIO. + */ + + dev_dbg(&indio_dev->dev, "%s: pos = %d, available = %d\n", __func__, + adc->bufi, available); + old_pos = adc->bufi; + + while (available >= indio_dev->scan_bytes) { + u32 *buffer = (u32 *)&adc->rx_buf[adc->bufi]; + + /* Mask 8 LSB that contains the channel ID */ + *buffer = (*buffer & 0xFFFFFF00) << 8; + available -= indio_dev->scan_bytes; + adc->bufi += indio_dev->scan_bytes; + if (adc->bufi >= adc->buf_sz) { + if (adc->cb) + adc->cb(&adc->rx_buf[old_pos], + adc->buf_sz - old_pos, adc->cb_priv); + adc->bufi = 0; + old_pos = 0; + } + } + if (adc->cb) + adc->cb(&adc->rx_buf[old_pos], adc->bufi - old_pos, + adc->cb_priv); +} + +static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + struct dma_async_tx_descriptor *desc; + dma_cookie_t cookie; + int ret; + + if (!adc->dma_chan) + return -EINVAL; + + dev_dbg(&indio_dev->dev, "%s size=%d watermark=%d\n", __func__, + adc->buf_sz, adc->buf_sz / 2); + + /* Prepare a DMA cyclic transaction */ + desc = dmaengine_prep_dma_cyclic(adc->dma_chan, + adc->dma_buf, + adc->buf_sz, adc->buf_sz / 2, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!desc) + return -EBUSY; + + desc->callback = stm32_dfsdm_audio_dma_buffer_done; + desc->callback_param = indio_dev; + + cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); + if (ret) { + dmaengine_terminate_all(adc->dma_chan); + return ret; + } + + /* Issue pending DMA requests */ + dma_async_issue_pending(adc->dma_chan); + + return 0; +} + +static int stm32_dfsdm_postenable(struct iio_dev *indio_dev) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + int ret; + + /* Reset adc buffer index */ + adc->bufi = 0; + + ret = stm32_dfsdm_start_dfsdm(adc->dfsdm); + if (ret < 0) + return ret; + + ret = stm32_dfsdm_start_conv(adc, true); + if (ret) { + dev_err(&indio_dev->dev, "Can't start conversion\n"); + goto stop_dfsdm; + } + + if (adc->dma_chan) { + ret = stm32_dfsdm_adc_dma_start(indio_dev); + if (ret) { + dev_err(&indio_dev->dev, "Can't start DMA\n"); + goto err_stop_conv; + } + } + + return 0; + +err_stop_conv: + stm32_dfsdm_stop_conv(adc); +stop_dfsdm: + stm32_dfsdm_stop_dfsdm(adc->dfsdm); + + return ret; +} + +static int stm32_dfsdm_predisable(struct iio_dev *indio_dev) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + + if (adc->dma_chan) + dmaengine_terminate_all(adc->dma_chan); + + stm32_dfsdm_stop_conv(adc); + + stm32_dfsdm_stop_dfsdm(adc->dfsdm); + + return 0; +} + +static const struct iio_buffer_setup_ops stm32_dfsdm_buffer_setup_ops = { + .postenable = &stm32_dfsdm_postenable, + .predisable = &stm32_dfsdm_predisable, +}; + +/** + * stm32_dfsdm_get_buff_cb() - register a callback that will be called when + * DMA transfer period is achieved. + * + * @iio_dev: Handle to IIO device. + * @cb: Pointer to callback function: + * - data: pointer to data buffer + * - size: size in byte of the data buffer + * - private: pointer to consumer private structure. + * @private: Pointer to consumer private structure. + */ +int stm32_dfsdm_get_buff_cb(struct iio_dev *iio_dev, + int (*cb)(const void *data, size_t size, + void *private), + void *private) +{ + struct stm32_dfsdm_adc *adc; + + if (!iio_dev) + return -EINVAL; + adc = iio_priv(iio_dev); + + adc->cb = cb; + adc->cb_priv = private; + + return 0; +} +EXPORT_SYMBOL_GPL(stm32_dfsdm_get_buff_cb); + +/** + * stm32_dfsdm_release_buff_cb - unregister buffer callback + * + * @iio_dev: Handle to IIO device. + */ +int stm32_dfsdm_release_buff_cb(struct iio_dev *iio_dev) +{ + struct stm32_dfsdm_adc *adc; + + if (!iio_dev) + return -EINVAL; + adc = iio_priv(iio_dev); + + adc->cb = NULL; + adc->cb_priv = NULL; + + return 0; +} +EXPORT_SYMBOL_GPL(stm32_dfsdm_release_buff_cb); + static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, int *res) { @@ -453,15 +765,41 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; + struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[adc->ch_id]; + unsigned int spi_freq = adc->spi_freq; int ret = -EINVAL; - if (mask == IIO_CHAN_INFO_OVERSAMPLING_RATIO) { + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: ret = stm32_dfsdm_set_osrs(fl, 0, val); if (!ret) adc->oversamp = val; + + return ret; + + case IIO_CHAN_INFO_SAMP_FREQ: + if (!val) + return -EINVAL; + if (ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL) + spi_freq = adc->dfsdm->spi_master_freq; + + if (spi_freq % val) + dev_warn(&indio_dev->dev, + "Sampling rate not accurate (%d)\n", + spi_freq / (spi_freq / val)); + + ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / val)); + if (ret < 0) { + dev_err(&indio_dev->dev, + "Not able to find parameter that match!\n"); + return ret; + } + adc->sample_freq = val; + + return 0; } - return ret; + return -EINVAL; } static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, @@ -493,12 +831,23 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_OVERSAMPLING_RATIO: *val = adc->oversamp; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SAMP_FREQ: + *val = adc->sample_freq; + return IIO_VAL_INT; } return -EINVAL; } +static const struct iio_info stm32_dfsdm_info_audio = { + .hwfifo_set_watermark = stm32_dfsdm_set_watermark, + .read_raw = stm32_dfsdm_read_raw, + .write_raw = stm32_dfsdm_write_raw, +}; + static const struct iio_info stm32_dfsdm_info_adc = { .read_raw = stm32_dfsdm_read_raw, .write_raw = stm32_dfsdm_write_raw, @@ -531,6 +880,70 @@ static irqreturn_t stm32_dfsdm_irq(int irq, void *arg) return IRQ_HANDLED; } +/* + * Define external info for SPI Frequency and audio sampling rate that can be + * configured by ASoC driver through consumer.h API + */ +static const struct iio_chan_spec_ext_info dfsdm_adc_audio_ext_info[] = { + /* spi_clk_freq : clock freq on SPI/manchester bus used by channel */ + { + .name = "spi_clk_freq", + .shared = IIO_SHARED_BY_TYPE, + .read = dfsdm_adc_audio_get_spiclk, + .write = dfsdm_adc_audio_set_spiclk, + }, + {}, +}; + +static void stm32_dfsdm_dma_release(struct iio_dev *indio_dev) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + + if (adc->dma_chan) { + dma_free_coherent(adc->dma_chan->device->dev, + DFSDM_DMA_BUFFER_SIZE, + adc->rx_buf, adc->dma_buf); + dma_release_channel(adc->dma_chan); + } +} + +static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + struct dma_slave_config config = { + .src_addr = (dma_addr_t)adc->dfsdm->phys_base + + DFSDM_RDATAR(adc->fl_id), + .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, + }; + int ret; + + adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx"); + if (!adc->dma_chan) + return -EINVAL; + + adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev, + DFSDM_DMA_BUFFER_SIZE, + &adc->dma_buf, GFP_KERNEL); + if (!adc->rx_buf) { + ret = -ENOMEM; + goto err_release; + } + + ret = dmaengine_slave_config(adc->dma_chan, &config); + if (ret) + goto err_free; + + return 0; + +err_free: + dma_free_coherent(adc->dma_chan->device->dev, DFSDM_DMA_BUFFER_SIZE, + adc->rx_buf, adc->dma_buf); +err_release: + dma_release_channel(adc->dma_chan); + + return ret; +} + static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, struct iio_chan_spec *ch) { @@ -551,7 +964,12 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); - ch->scan_type.sign = 'u'; + if (adc->dev_data->type == DFSDM_AUDIO) { + ch->scan_type.sign = 's'; + ch->ext_info = dfsdm_adc_audio_ext_info; + } else { + ch->scan_type.sign = 'u'; + } ch->scan_type.realbits = 24; ch->scan_type.storagebits = 32; adc->ch_id = ch->channel; @@ -560,6 +978,39 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, &adc->dfsdm->ch_list[ch->channel]); } +static int stm32_dfsdm_audio_init(struct iio_dev *indio_dev) +{ + struct iio_chan_spec *ch; + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); + struct stm32_dfsdm_channel *d_ch; + int ret; + + indio_dev->modes |= INDIO_BUFFER_SOFTWARE; + indio_dev->setup_ops = &stm32_dfsdm_buffer_setup_ops; + + ch = devm_kzalloc(&indio_dev->dev, sizeof(*ch), GFP_KERNEL); + if (!ch) + return -ENOMEM; + + ch->scan_index = 0; + + ret = stm32_dfsdm_adc_chan_init_one(indio_dev, ch); + if (ret < 0) { + dev_err(&indio_dev->dev, "Channels init failed\n"); + return ret; + } + ch->info_mask_separate = BIT(IIO_CHAN_INFO_SAMP_FREQ); + + d_ch = &adc->dfsdm->ch_list[adc->ch_id]; + if (d_ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL) + adc->spi_freq = adc->dfsdm->spi_master_freq; + + indio_dev->num_channels = 1; + indio_dev->channels = ch; + + return stm32_dfsdm_dma_request(indio_dev); +} + static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) { struct iio_chan_spec *ch; @@ -612,11 +1063,20 @@ static const struct stm32_dfsdm_dev_data stm32h7_dfsdm_adc_data = { .init = stm32_dfsdm_adc_init, }; +static const struct stm32_dfsdm_dev_data stm32h7_dfsdm_audio_data = { + .type = DFSDM_AUDIO, + .init = stm32_dfsdm_audio_init, +}; + static const struct of_device_id stm32_dfsdm_adc_match[] = { { .compatible = "st,stm32-dfsdm-adc", .data = &stm32h7_dfsdm_adc_data, }, + { + .compatible = "st,stm32-dfsdm-dmic", + .data = &stm32h7_dfsdm_audio_data, + }, {} }; @@ -667,8 +1127,13 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) name = devm_kzalloc(dev, sizeof("dfsdm-adc0"), GFP_KERNEL); if (!name) return -ENOMEM; - iio->info = &stm32_dfsdm_info_adc; - snprintf(name, sizeof("dfsdm-adc0"), "dfsdm-adc%d", adc->fl_id); + if (dev_data->type == DFSDM_AUDIO) { + iio->info = &stm32_dfsdm_info_audio; + snprintf(name, sizeof("dfsdm-pdm0"), "dfsdm-pdm%d", adc->fl_id); + } else { + iio->info = &stm32_dfsdm_info_adc; + snprintf(name, sizeof("dfsdm-adc0"), "dfsdm-adc%d", adc->fl_id); + } iio->name = name; /* @@ -700,7 +1165,27 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) if (ret < 0) return ret; - return iio_device_register(iio); + ret = iio_device_register(iio); + if (ret < 0) + goto err_cleanup; + + dev_err(dev, "of_platform_populate\n"); + if (dev_data->type == DFSDM_AUDIO) { + ret = of_platform_populate(np, NULL, NULL, dev); + if (ret < 0) { + dev_err(dev, "Failed to find an audio DAI\n"); + goto err_unregister; + } + } + + return 0; + +err_unregister: + iio_device_unregister(iio); +err_cleanup: + stm32_dfsdm_dma_release(iio); + + return ret; } static int stm32_dfsdm_adc_remove(struct platform_device *pdev) @@ -708,7 +1193,10 @@ static int stm32_dfsdm_adc_remove(struct platform_device *pdev) struct stm32_dfsdm_adc *adc = platform_get_drvdata(pdev); struct iio_dev *indio_dev = iio_priv_to_dev(adc); + if (adc->dev_data->type == DFSDM_AUDIO) + of_platform_depopulate(&pdev->dev); iio_device_unregister(indio_dev); + stm32_dfsdm_dma_release(indio_dev); return 0; } diff --git a/include/linux/iio/adc/stm32-dfsdm-adc.h b/include/linux/iio/adc/stm32-dfsdm-adc.h new file mode 100644 index 000000000000..e7dc7a542a4e --- /dev/null +++ b/include/linux/iio/adc/stm32-dfsdm-adc.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This file discribe the STM32 DFSDM IIO driver API for audio part + * + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Arnaud Pouliquen . + */ + +#ifndef STM32_DFSDM_ADC_H +#define STM32_DFSDM_ADC_H + +int stm32_dfsdm_get_buff_cb(struct iio_dev *iio_dev, + int (*cb)(const void *data, size_t size, + void *private), + void *private); +int stm32_dfsdm_release_buff_cb(struct iio_dev *iio_dev); + +#endif -- cgit v1.2.3 From 16cbca06fa8288a4f58426fc898b141e12ee8008 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Wed, 10 Jan 2018 11:13:13 +0100 Subject: IIO: consumer: allow to set buffer sizes Add iio consumer API to set buffer size and watermark according to sysfs API. Signed-off-by: Arnaud Pouliquen Reviewed-by: Jonathan Cameron Signed-off-by: Mark Brown --- drivers/iio/buffer/industrialio-buffer-cb.c | 11 +++++++++++ include/linux/iio/consumer.h | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/drivers/iio/buffer/industrialio-buffer-cb.c b/drivers/iio/buffer/industrialio-buffer-cb.c index 4847534700e7..ea63c838eeae 100644 --- a/drivers/iio/buffer/industrialio-buffer-cb.c +++ b/drivers/iio/buffer/industrialio-buffer-cb.c @@ -104,6 +104,17 @@ error_free_cb_buff: } EXPORT_SYMBOL_GPL(iio_channel_get_all_cb); +int iio_channel_cb_set_buffer_watermark(struct iio_cb_buffer *cb_buff, + size_t watermark) +{ + if (!watermark) + return -EINVAL; + cb_buff->buffer.watermark = watermark; + + return 0; +} +EXPORT_SYMBOL_GPL(iio_channel_cb_set_buffer_watermark); + int iio_channel_start_all_cb(struct iio_cb_buffer *cb_buff) { return iio_update_buffers(cb_buff->indio_dev, &cb_buff->buffer, diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 2017f35db17c..9887f4f8e2a8 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -133,6 +133,17 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, int (*cb)(const void *data, void *private), void *private); +/** + * iio_channel_cb_set_buffer_watermark() - set the buffer watermark. + * @cb_buffer: The callback buffer from whom we want the channel + * information. + * @watermark: buffer watermark in bytes. + * + * This function allows to configure the buffer watermark. + */ +int iio_channel_cb_set_buffer_watermark(struct iio_cb_buffer *cb_buffer, + size_t watermark); + /** * iio_channel_release_all_cb() - release and unregister the callback. * @cb_buffer: The callback buffer that was allocated. -- cgit v1.2.3 From a71615792d0b341500a9d1d7b374d19e3d443a12 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Wed, 10 Jan 2018 11:13:14 +0100 Subject: ASoC: add bindings for stm32 DFSDM filter Add bindings that describes audio settings to support Digital Filter for pulse density modulation(PDM) microphone. Signed-off-by: Arnaud Pouliquen Acked-by: Rob Herring Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/st,stm32-adfsdm.txt | 63 ++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt diff --git a/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt b/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt new file mode 100644 index 000000000000..864f5b00b031 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt @@ -0,0 +1,63 @@ +STMicroelectronics Audio Digital Filter Sigma Delta modulators(DFSDM) + +The DFSDM allows PDM microphones capture through SPI interface. The Audio +interface is seems as a sub block of the DFSDM device. +For details on DFSDM bindings refer to ../iio/adc/st,stm32-dfsdm-adc.txt + +Required properties: + - compatible: "st,stm32h7-dfsdm-dai". + + - #sound-dai-cells : Must be equal to 0 + + - io-channels : phandle to iio dfsdm instance node. + +Example of a sound card using audio DFSDM node. + + sound_card { + compatible = "audio-graph-card"; + + dais = <&cpu_port>; + }; + + dfsdm: dfsdm@40017000 { + compatible = "st,stm32h7-dfsdm"; + reg = <0x40017000 0x400>; + clocks = <&rcc DFSDM1_CK>; + clock-names = "dfsdm"; + #interrupt-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + dfsdm_adc0: filter@0 { + compatible = "st,stm32-dfsdm-dmic"; + reg = <0>; + interrupts = <110>; + dmas = <&dmamux1 101 0x400 0x00>; + dma-names = "rx"; + st,adc-channels = <1>; + st,adc-channel-names = "dmic0"; + st,adc-channel-types = "SPI_R"; + st,adc-channel-clk-src = "CLKOUT"; + st,filter-order = <5>; + + dfsdm_dai0: dfsdm-dai { + compatible = "st,stm32h7-dfsdm-dai"; + #sound-dai-cells = <0>; + io-channels = <&dfsdm_adc0 0>; + cpu_port: port { + dfsdm_endpoint: endpoint { + remote-endpoint = <&dmic0_endpoint>; + }; + }; + }; + }; + + dmic0: dmic@0 { + compatible = "dmic-codec"; + #sound-dai-cells = <0>; + port { + dmic0_endpoint: endpoint { + remote-endpoint = <&dfsdm_endpoint>; + }; + }; + }; -- cgit v1.2.3 From 55da094824c4ef1d50bc591733d79448d00265bb Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Wed, 10 Jan 2018 11:13:15 +0100 Subject: ASoC: stm32: add DFSDM DAI support Add driver to handle DAI interface for PDM microphones connected to Digital Filter for Sigma Delta Modulators IP. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/stm/Kconfig | 11 ++ sound/soc/stm/Makefile | 3 + sound/soc/stm/stm32_adfsdm.c | 347 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 361 insertions(+) create mode 100644 sound/soc/stm/stm32_adfsdm.c diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index 3398e6c57f37..a78f7700d489 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -28,4 +28,15 @@ config SND_SOC_STM32_SPDIFRX help Say Y if you want to enable S/PDIF capture for STM32 +config SND_SOC_STM32_DFSDM + tristate "SoC Audio support for STM32 DFSDM" + depends on (ARCH_STM32 && OF && STM32_DFSDM_ADC) || COMPILE_TEST + depends on SND_SOC + select SND_SOC_GENERIC_DMAENGINE_PCM + select SND_SOC_DMIC + select IIO_BUFFER_CB + help + Select this option to enable the STM32 Digital Filter + for Sigma Delta Modulators (DFSDM) driver used + in various STM32 series for digital microphone capture. endmenu diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile index 5b7f0fab0bd6..3143c0b47042 100644 --- a/sound/soc/stm/Makefile +++ b/sound/soc/stm/Makefile @@ -13,3 +13,6 @@ obj-$(CONFIG_SND_SOC_STM32_I2S) += snd-soc-stm32-i2s.o # SPDIFRX snd-soc-stm32-spdifrx-objs := stm32_spdifrx.o obj-$(CONFIG_SND_SOC_STM32_SPDIFRX) += snd-soc-stm32-spdifrx.o + +#DFSDM +obj-$(CONFIG_SND_SOC_STM32_DFSDM) += stm32_adfsdm.o diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c new file mode 100644 index 000000000000..af50891983c6 --- /dev/null +++ b/sound/soc/stm/stm32_adfsdm.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This file is part of STM32 DFSDM ASoC DAI driver + * + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Authors: Arnaud Pouliquen + * Olivier Moysan + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define STM32_ADFSDM_DRV_NAME "stm32-adfsdm" + +#define DFSDM_MAX_PERIOD_SIZE (PAGE_SIZE / 2) +#define DFSDM_MAX_PERIODS 6 + +struct stm32_adfsdm_priv { + struct snd_soc_dai_driver dai_drv; + struct snd_pcm_substream *substream; + struct device *dev; + + /* IIO */ + struct iio_channel *iio_ch; + struct iio_cb_buffer *iio_cb; + bool iio_active; + + /* PCM buffer */ + unsigned char *pcm_buff; + unsigned int pos; +}; + +static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + + .rate_min = 8000, + .rate_max = 32000, + + .channels_min = 1, + .channels_max = 1, + + .periods_min = 2, + .periods_max = DFSDM_MAX_PERIODS, + + .period_bytes_max = DFSDM_MAX_PERIOD_SIZE, + .buffer_bytes_max = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE +}; + +static void stm32_adfsdm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai); + + if (priv->iio_active) { + iio_channel_stop_all_cb(priv->iio_cb); + priv->iio_active = false; + } +} + +static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai); + int ret; + + ret = iio_write_channel_attribute(priv->iio_ch, + substream->runtime->rate, 0, + IIO_CHAN_INFO_SAMP_FREQ); + if (ret < 0) { + dev_err(dai->dev, "%s: Failed to set %d sampling rate\n", + __func__, substream->runtime->rate); + return ret; + } + + if (!priv->iio_active) { + ret = iio_channel_start_all_cb(priv->iio_cb); + if (!ret) + priv->iio_active = true; + else + dev_err(dai->dev, "%s: IIO channel start failed (%d)\n", + __func__, ret); + } + + return ret; +} + +static int stm32_adfsdm_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai); + ssize_t size; + char str_freq[10]; + + dev_dbg(dai->dev, "%s: Enter for freq %d\n", __func__, freq); + + /* Set IIO frequency if CODEC is master as clock comes from SPI_IN */ + + snprintf(str_freq, sizeof(str_freq), "%d\n", freq); + size = iio_write_channel_ext_info(priv->iio_ch, "spi_clk_freq", + str_freq, sizeof(str_freq)); + if (size != sizeof(str_freq)) { + dev_err(dai->dev, "%s: Failed to set SPI clock\n", + __func__); + return -EINVAL; + } + return 0; +} + +static const struct snd_soc_dai_ops stm32_adfsdm_dai_ops = { + .shutdown = stm32_adfsdm_shutdown, + .prepare = stm32_adfsdm_dai_prepare, + .set_sysclk = stm32_adfsdm_set_sysclk, +}; + +static const struct snd_soc_dai_driver stm32_adfsdm_dai = { + .capture = { + .channels_min = 1, + .channels_max = 1, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000), + }, + .ops = &stm32_adfsdm_dai_ops, +}; + +static const struct snd_soc_component_driver stm32_adfsdm_dai_component = { + .name = "stm32_dfsdm_audio", +}; + +static int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private) +{ + struct stm32_adfsdm_priv *priv = private; + struct snd_soc_pcm_runtime *rtd = priv->substream->private_data; + u8 *pcm_buff = priv->pcm_buff; + u8 *src_buff = (u8 *)data; + unsigned int buff_size = snd_pcm_lib_buffer_bytes(priv->substream); + unsigned int period_size = snd_pcm_lib_period_bytes(priv->substream); + unsigned int old_pos = priv->pos; + unsigned int cur_size = size; + + dev_dbg(rtd->dev, "%s: buff_add :%p, pos = %d, size = %zu\n", + __func__, &pcm_buff[priv->pos], priv->pos, size); + + if ((priv->pos + size) > buff_size) { + memcpy(&pcm_buff[priv->pos], src_buff, buff_size - priv->pos); + cur_size -= buff_size - priv->pos; + priv->pos = 0; + } + + memcpy(&pcm_buff[priv->pos], &src_buff[size - cur_size], cur_size); + priv->pos = (priv->pos + cur_size) % buff_size; + + if (cur_size != size || (old_pos && (old_pos % period_size < size))) + snd_pcm_period_elapsed(priv->substream); + + return 0; +} + +static int stm32_adfsdm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct stm32_adfsdm_priv *priv = + snd_soc_dai_get_drvdata(rtd->cpu_dai); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + priv->pos = 0; + return stm32_dfsdm_get_buff_cb(priv->iio_ch->indio_dev, + stm32_afsdm_pcm_cb, priv); + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + return stm32_dfsdm_release_buff_cb(priv->iio_ch->indio_dev); + } + + return -EINVAL; +} + +static int stm32_adfsdm_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); + int ret; + + ret = snd_soc_set_runtime_hwparams(substream, &stm32_adfsdm_pcm_hw); + if (!ret) + priv->substream = substream; + + return ret; +} + +static int stm32_adfsdm_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct stm32_adfsdm_priv *priv = + snd_soc_dai_get_drvdata(rtd->cpu_dai); + + snd_pcm_lib_free_pages(substream); + priv->substream = NULL; + + return 0; +} + +static snd_pcm_uframes_t stm32_adfsdm_pcm_pointer( + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct stm32_adfsdm_priv *priv = + snd_soc_dai_get_drvdata(rtd->cpu_dai); + + return bytes_to_frames(substream->runtime, priv->pos); +} + +static int stm32_adfsdm_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct stm32_adfsdm_priv *priv = + snd_soc_dai_get_drvdata(rtd->cpu_dai); + int ret; + + ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); + if (ret < 0) + return ret; + priv->pcm_buff = substream->runtime->dma_area; + + return iio_channel_cb_set_buffer_watermark(priv->iio_cb, + params_period_size(params)); +} + +static int stm32_adfsdm_pcm_hw_free(struct snd_pcm_substream *substream) +{ + snd_pcm_lib_free_pages(substream); + + return 0; +} + +static struct snd_pcm_ops stm32_adfsdm_pcm_ops = { + .open = stm32_adfsdm_pcm_open, + .close = stm32_adfsdm_pcm_close, + .hw_params = stm32_adfsdm_pcm_hw_params, + .hw_free = stm32_adfsdm_pcm_hw_free, + .trigger = stm32_adfsdm_trigger, + .pointer = stm32_adfsdm_pcm_pointer, +}; + +static int stm32_adfsdm_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_pcm *pcm = rtd->pcm; + struct stm32_adfsdm_priv *priv = + snd_soc_dai_get_drvdata(rtd->cpu_dai); + unsigned int size = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE; + + return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + priv->dev, size, size); +} + +static void stm32_adfsdm_pcm_free(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_soc_pcm_runtime *rtd; + struct stm32_adfsdm_priv *priv; + + substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + if (substream) { + rtd = substream->private_data; + priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); + + snd_pcm_lib_preallocate_free_for_all(pcm); + } +} + +static struct snd_soc_platform_driver stm32_adfsdm_soc_platform = { + .ops = &stm32_adfsdm_pcm_ops, + .pcm_new = stm32_adfsdm_pcm_new, + .pcm_free = stm32_adfsdm_pcm_free, +}; + +static const struct of_device_id stm32_adfsdm_of_match[] = { + {.compatible = "st,stm32h7-dfsdm-dai"}, + {} +}; +MODULE_DEVICE_TABLE(of, stm32_adfsdm_of_match); + +static int stm32_adfsdm_probe(struct platform_device *pdev) +{ + struct stm32_adfsdm_priv *priv; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + priv->dai_drv = stm32_adfsdm_dai; + + dev_set_drvdata(&pdev->dev, priv); + + ret = devm_snd_soc_register_component(&pdev->dev, + &stm32_adfsdm_dai_component, + &priv->dai_drv, 1); + if (ret < 0) + return ret; + + /* Associate iio channel */ + priv->iio_ch = devm_iio_channel_get_all(&pdev->dev); + if (IS_ERR(priv->iio_ch)) + return PTR_ERR(priv->iio_ch); + + priv->iio_cb = iio_channel_get_all_cb(&pdev->dev, NULL, NULL); + if (IS_ERR(priv->iio_cb)) + return PTR_ERR(priv->iio_ch); + + ret = devm_snd_soc_register_platform(&pdev->dev, + &stm32_adfsdm_soc_platform); + if (ret < 0) + dev_err(&pdev->dev, "%s: Failed to register PCM platform\n", + __func__); + + return ret; +} + +static struct platform_driver stm32_adfsdm_driver = { + .driver = { + .name = STM32_ADFSDM_DRV_NAME, + .of_match_table = stm32_adfsdm_of_match, + }, + .probe = stm32_adfsdm_probe, +}; + +module_platform_driver(stm32_adfsdm_driver); + +MODULE_DESCRIPTION("stm32 DFSDM DAI driver"); +MODULE_AUTHOR("Arnaud Pouliquen "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" STM32_ADFSDM_DRV_NAME); -- cgit v1.2.3 From 05f4434bc13030ca67f229b8defd37f12a05d1fa Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 10 Jan 2018 15:59:34 +0530 Subject: ASoC: Intel: remove mfld_machine mfld_machine was not getting compiled due to missed Makefile changes. Since no one complained it is safe to assume that it is not being used, so remove it Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 14 -- sound/soc/intel/boards/mfld_machine.c | 430 ---------------------------------- 2 files changed, 444 deletions(-) delete mode 100644 sound/soc/intel/boards/mfld_machine.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 12761d8fd8a5..de598dcbef30 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -12,20 +12,6 @@ menuconfig SND_SOC_INTEL_MACH if SND_SOC_INTEL_MACH -if SND_SST_ATOM_HIFI2_PLATFORM_PCI - -config SND_MFLD_MACHINE - tristate "Medfield (Intel MID)" - depends on INTEL_SCU_IPC - select SND_SOC_SN95031 - help - This adds support for ASoC machine driver for Intel(R) MID Medfield platform - used as alsa device in audio substem in Intel(R) MID devices - Say Y if you have such a device. - If unsure select "N". - -endif ## SND_SST_ATOM_HIFI2_PLATFORM_PCI - if SND_SOC_INTEL_HASWELL config SND_SOC_INTEL_HASWELL_MACH diff --git a/sound/soc/intel/boards/mfld_machine.c b/sound/soc/intel/boards/mfld_machine.c deleted file mode 100644 index 7cb44fdde1ee..000000000000 --- a/sound/soc/intel/boards/mfld_machine.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * mfld_machine.c - ASoc Machine driver for Intel Medfield MID platform - * - * Copyright (C) 2010 Intel Corp - * Author: Vinod Koul - * Author: Harsha Priya - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../codecs/sn95031.h" - -#define MID_MONO 1 -#define MID_STEREO 2 -#define MID_MAX_CAP 5 -#define MFLD_JACK_INSERT 0x04 - -enum soc_mic_bias_zones { - MFLD_MV_START = 0, - /* mic bias volutage range for Headphones*/ - MFLD_MV_HP = 400, - /* mic bias volutage range for American Headset*/ - MFLD_MV_AM_HS = 650, - /* mic bias volutage range for Headset*/ - MFLD_MV_HS = 2000, - MFLD_MV_UNDEFINED, -}; - -static unsigned int hs_switch; -static unsigned int lo_dac; -static struct snd_soc_codec *mfld_codec; - -struct mfld_mc_private { - void __iomem *int_base; - u8 interrupt_status; -}; - -struct snd_soc_jack mfld_jack; - -/*Headset jack detection DAPM pins */ -static struct snd_soc_jack_pin mfld_jack_pins[] = { - { - .pin = "Headphones", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "AMIC1", - .mask = SND_JACK_MICROPHONE, - }, -}; - -/* jack detection voltage zones */ -static struct snd_soc_jack_zone mfld_zones[] = { - {MFLD_MV_START, MFLD_MV_AM_HS, SND_JACK_HEADPHONE}, - {MFLD_MV_AM_HS, MFLD_MV_HS, SND_JACK_HEADSET}, -}; - -/* sound card controls */ -static const char * const headset_switch_text[] = {"Earpiece", "Headset"}; - -static const char * const lo_text[] = {"Vibra", "Headset", "IHF", "None"}; - -static const struct soc_enum headset_enum = - SOC_ENUM_SINGLE_EXT(2, headset_switch_text); - -static const struct soc_enum lo_enum = - SOC_ENUM_SINGLE_EXT(4, lo_text); - -static int headset_get_switch(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = hs_switch; - return 0; -} - -static int headset_set_switch(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_context *dapm = &card->dapm; - - if (ucontrol->value.enumerated.item[0] == hs_switch) - return 0; - - snd_soc_dapm_mutex_lock(dapm); - - if (ucontrol->value.enumerated.item[0]) { - pr_debug("hs_set HS path\n"); - snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones"); - snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT"); - } else { - pr_debug("hs_set EP path\n"); - snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones"); - snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT"); - } - - snd_soc_dapm_sync_unlocked(dapm); - - snd_soc_dapm_mutex_unlock(dapm); - - hs_switch = ucontrol->value.enumerated.item[0]; - - return 0; -} - -static void lo_enable_out_pins(struct snd_soc_dapm_context *dapm) -{ - snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL"); - snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR"); - snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL"); - snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTR"); - snd_soc_dapm_enable_pin_unlocked(dapm, "VIB1OUT"); - snd_soc_dapm_enable_pin_unlocked(dapm, "VIB2OUT"); - if (hs_switch) { - snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones"); - snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT"); - } else { - snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones"); - snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT"); - } -} - -static int lo_get_switch(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = lo_dac; - return 0; -} - -static int lo_set_switch(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_context *dapm = &card->dapm; - - if (ucontrol->value.enumerated.item[0] == lo_dac) - return 0; - - snd_soc_dapm_mutex_lock(dapm); - - /* we dont want to work with last state of lineout so just enable all - * pins and then disable pins not required - */ - lo_enable_out_pins(dapm); - - switch (ucontrol->value.enumerated.item[0]) { - case 0: - pr_debug("set vibra path\n"); - snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT"); - snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT"); - snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0); - break; - - case 1: - pr_debug("set hs path\n"); - snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones"); - snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT"); - snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x22); - break; - - case 2: - pr_debug("set spkr path\n"); - snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL"); - snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR"); - snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x44); - break; - - case 3: - pr_debug("set null path\n"); - snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL"); - snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR"); - snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x66); - break; - } - - snd_soc_dapm_sync_unlocked(dapm); - - snd_soc_dapm_mutex_unlock(dapm); - - lo_dac = ucontrol->value.enumerated.item[0]; - return 0; -} - -static const struct snd_kcontrol_new mfld_snd_controls[] = { - SOC_ENUM_EXT("Playback Switch", headset_enum, - headset_get_switch, headset_set_switch), - SOC_ENUM_EXT("Lineout Mux", lo_enum, - lo_get_switch, lo_set_switch), -}; - -static const struct snd_soc_dapm_widget mfld_widgets[] = { - SND_SOC_DAPM_HP("Headphones", NULL), - SND_SOC_DAPM_MIC("Mic", NULL), -}; - -static const struct snd_soc_dapm_route mfld_map[] = { - {"Headphones", NULL, "HPOUTR"}, - {"Headphones", NULL, "HPOUTL"}, - {"Mic", NULL, "AMIC1"}, -}; - -static void mfld_jack_check(unsigned int intr_status) -{ - struct mfld_jack_data jack_data; - - if (!mfld_codec) - return; - - jack_data.mfld_jack = &mfld_jack; - jack_data.intr_id = intr_status; - - sn95031_jack_detection(mfld_codec, &jack_data); - /* TODO: add american headset detection post gpiolib support */ -} - -static int mfld_init(struct snd_soc_pcm_runtime *runtime) -{ - struct snd_soc_dapm_context *dapm = &runtime->card->dapm; - int ret_val; - - /* default is earpiece pin, userspace sets it explcitly */ - snd_soc_dapm_disable_pin(dapm, "Headphones"); - /* default is lineout NC, userspace sets it explcitly */ - snd_soc_dapm_disable_pin(dapm, "LINEOUTL"); - snd_soc_dapm_disable_pin(dapm, "LINEOUTR"); - lo_dac = 3; - hs_switch = 0; - /* we dont use linein in this so set to NC */ - snd_soc_dapm_disable_pin(dapm, "LINEINL"); - snd_soc_dapm_disable_pin(dapm, "LINEINR"); - - /* Headset and button jack detection */ - ret_val = snd_soc_card_jack_new(runtime->card, - "Intel(R) MID Audio Jack", SND_JACK_HEADSET | - SND_JACK_BTN_0 | SND_JACK_BTN_1, &mfld_jack, - mfld_jack_pins, ARRAY_SIZE(mfld_jack_pins)); - if (ret_val) { - pr_err("jack creation failed\n"); - return ret_val; - } - - ret_val = snd_soc_jack_add_zones(&mfld_jack, - ARRAY_SIZE(mfld_zones), mfld_zones); - if (ret_val) { - pr_err("adding jack zones failed\n"); - return ret_val; - } - - mfld_codec = runtime->codec; - - /* we want to check if anything is inserted at boot, - * so send a fake event to codec and it will read adc - * to find if anything is there or not */ - mfld_jack_check(MFLD_JACK_INSERT); - return ret_val; -} - -static struct snd_soc_dai_link mfld_msic_dailink[] = { - { - .name = "Medfield Headset", - .stream_name = "Headset", - .cpu_dai_name = "Headset-cpu-dai", - .codec_dai_name = "SN95031 Headset", - .codec_name = "sn95031", - .platform_name = "sst-platform", - .init = mfld_init, - }, - { - .name = "Medfield Speaker", - .stream_name = "Speaker", - .cpu_dai_name = "Speaker-cpu-dai", - .codec_dai_name = "SN95031 Speaker", - .codec_name = "sn95031", - .platform_name = "sst-platform", - .init = NULL, - }, - { - .name = "Medfield Vibra", - .stream_name = "Vibra1", - .cpu_dai_name = "Vibra1-cpu-dai", - .codec_dai_name = "SN95031 Vibra1", - .codec_name = "sn95031", - .platform_name = "sst-platform", - .init = NULL, - }, - { - .name = "Medfield Haptics", - .stream_name = "Vibra2", - .cpu_dai_name = "Vibra2-cpu-dai", - .codec_dai_name = "SN95031 Vibra2", - .codec_name = "sn95031", - .platform_name = "sst-platform", - .init = NULL, - }, - { - .name = "Medfield Compress", - .stream_name = "Speaker", - .cpu_dai_name = "Compress-cpu-dai", - .codec_dai_name = "SN95031 Speaker", - .codec_name = "sn95031", - .platform_name = "sst-platform", - .init = NULL, - }, -}; - -/* SoC card */ -static struct snd_soc_card snd_soc_card_mfld = { - .name = "medfield_audio", - .owner = THIS_MODULE, - .dai_link = mfld_msic_dailink, - .num_links = ARRAY_SIZE(mfld_msic_dailink), - - .controls = mfld_snd_controls, - .num_controls = ARRAY_SIZE(mfld_snd_controls), - .dapm_widgets = mfld_widgets, - .num_dapm_widgets = ARRAY_SIZE(mfld_widgets), - .dapm_routes = mfld_map, - .num_dapm_routes = ARRAY_SIZE(mfld_map), -}; - -static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev) -{ - struct mfld_mc_private *mc_private = (struct mfld_mc_private *) dev; - - memcpy_fromio(&mc_private->interrupt_status, - ((void *)(mc_private->int_base)), - sizeof(u8)); - return IRQ_WAKE_THREAD; -} - -static irqreturn_t snd_mfld_jack_detection(int irq, void *data) -{ - struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data; - - mfld_jack_check(mc_drv_ctx->interrupt_status); - - return IRQ_HANDLED; -} - -static int snd_mfld_mc_probe(struct platform_device *pdev) -{ - int ret_val = 0, irq; - struct mfld_mc_private *mc_drv_ctx; - struct resource *irq_mem; - - pr_debug("snd_mfld_mc_probe called\n"); - - /* retrive the irq number */ - irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return irq < 0 ? irq : -ENODEV; - - /* audio interrupt base of SRAM location where - * interrupts are stored by System FW */ - mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC); - if (!mc_drv_ctx) - return -ENOMEM; - - irq_mem = platform_get_resource_byname( - pdev, IORESOURCE_MEM, "IRQ_BASE"); - if (!irq_mem) { - pr_err("no mem resource given\n"); - return -ENODEV; - } - mc_drv_ctx->int_base = devm_ioremap_nocache(&pdev->dev, irq_mem->start, - resource_size(irq_mem)); - if (!mc_drv_ctx->int_base) { - pr_err("Mapping of cache failed\n"); - return -ENOMEM; - } - /* register for interrupt */ - ret_val = devm_request_threaded_irq(&pdev->dev, irq, - snd_mfld_jack_intr_handler, - snd_mfld_jack_detection, - IRQF_SHARED, pdev->dev.driver->name, mc_drv_ctx); - if (ret_val) { - pr_err("cannot register IRQ\n"); - return ret_val; - } - /* register the soc card */ - snd_soc_card_mfld.dev = &pdev->dev; - ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_mfld); - if (ret_val) { - pr_debug("snd_soc_register_card failed %d\n", ret_val); - return ret_val; - } - platform_set_drvdata(pdev, mc_drv_ctx); - pr_debug("successfully exited probe\n"); - return 0; -} - -static struct platform_driver snd_mfld_mc_driver = { - .driver = { - .name = "msic_audio", - }, - .probe = snd_mfld_mc_probe, -}; - -module_platform_driver(snd_mfld_mc_driver); - -MODULE_DESCRIPTION("ASoC Intel(R) MID Machine driver"); -MODULE_AUTHOR("Vinod Koul "); -MODULE_AUTHOR("Harsha Priya "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:msic-audio"); -- cgit v1.2.3 From 987da3fe175933c28aab2293505c3597052ff0e2 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 10 Jan 2018 15:59:35 +0530 Subject: ASoC: sn95031: remove this code This codec was used in MFLD systems in the PMIC chip, we no longer have users for this, so remove it Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 - sound/soc/codecs/Makefile | 1 - sound/soc/codecs/sn95031.c | 936 --------------------------------------------- sound/soc/codecs/sn95031.h | 133 ------- 4 files changed, 1074 deletions(-) delete mode 100644 sound/soc/codecs/sn95031.c delete mode 100644 sound/soc/codecs/sn95031.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a42ddbc93f3d..3ed2b985b38b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -133,7 +133,6 @@ config SND_SOC_ALL_CODECS select SND_SOC_SGTL5000 if I2C select SND_SOC_SI476X if MFD_SI476X_CORE select SND_SOC_SIRF_AUDIO_CODEC - select SND_SOC_SN95031 if INTEL_SCU_IPC select SND_SOC_SPDIF select SND_SOC_SSM2518 if I2C select SND_SOC_SSM2602_SPI if SPI_MASTER @@ -818,9 +817,6 @@ config SND_SOC_SIRF_AUDIO_CODEC tristate "SiRF SoC internal audio codec" select REGMAP_MMIO -config SND_SOC_SN95031 - tristate - config SND_SOC_SPDIF tristate "S/PDIF CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 0001069ce2a7..ae25cbe85d1d 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -140,7 +140,6 @@ snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o snd-soc-si476x-objs := si476x.o snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o -snd-soc-sn95031-objs := sn95031.o snd-soc-spdif-tx-objs := spdif_transmitter.o snd-soc-spdif-rx-objs := spdif_receiver.o snd-soc-ssm2518-objs := ssm2518.o diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c deleted file mode 100644 index 887923e68849..000000000000 --- a/sound/soc/codecs/sn95031.c +++ /dev/null @@ -1,936 +0,0 @@ -/* - * sn95031.c - TI sn95031 Codec driver - * - * Copyright (C) 2010 Intel Corp - * Author: Vinod Koul - * Author: Harsha Priya - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * - */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "sn95031.h" - -#define SN95031_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100) -#define SN95031_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) - -/* adc helper functions */ - -/* enables mic bias voltage */ -static void sn95031_enable_mic_bias(struct snd_soc_codec *codec) -{ - snd_soc_write(codec, SN95031_VAUD, BIT(2)|BIT(1)|BIT(0)); - snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(2), BIT(2)); -} - -/* Enable/Disable the ADC depending on the argument */ -static void configure_adc(struct snd_soc_codec *sn95031_codec, int val) -{ - int value = snd_soc_read(sn95031_codec, SN95031_ADC1CNTL1); - - if (val) { - /* Enable and start the ADC */ - value |= (SN95031_ADC_ENBL | SN95031_ADC_START); - value &= (~SN95031_ADC_NO_LOOP); - } else { - /* Just stop the ADC */ - value &= (~SN95031_ADC_START); - } - snd_soc_write(sn95031_codec, SN95031_ADC1CNTL1, value); -} - -/* - * finds an empty channel for conversion - * If the ADC is not enabled then start using 0th channel - * itself. Otherwise find an empty channel by looking for a - * channel in which the stopbit is set to 1. returns the index - * of the first free channel if succeeds or an error code. - * - * Context: can sleep - * - */ -static int find_free_channel(struct snd_soc_codec *sn95031_codec) -{ - int i, value; - - /* check whether ADC is enabled */ - value = snd_soc_read(sn95031_codec, SN95031_ADC1CNTL1); - - if ((value & SN95031_ADC_ENBL) == 0) - return 0; - - /* ADC is already enabled; Looking for an empty channel */ - for (i = 0; i < SN95031_ADC_CHANLS_MAX; i++) { - value = snd_soc_read(sn95031_codec, - SN95031_ADC_CHNL_START_ADDR + i); - if (value & SN95031_STOPBIT_MASK) - break; - } - return (i == SN95031_ADC_CHANLS_MAX) ? (-EINVAL) : i; -} - -/* Initialize the ADC for reading micbias values. Can sleep. */ -static int sn95031_initialize_adc(struct snd_soc_codec *sn95031_codec) -{ - int base_addr, chnl_addr; - int value; - int channel_index; - - /* Index of the first channel in which the stop bit is set */ - channel_index = find_free_channel(sn95031_codec); - if (channel_index < 0) { - pr_err("No free ADC channels"); - return channel_index; - } - - base_addr = SN95031_ADC_CHNL_START_ADDR + channel_index; - - if (!(channel_index == 0 || channel_index == SN95031_ADC_LOOP_MAX)) { - /* Reset stop bit for channels other than 0 and 12 */ - value = snd_soc_read(sn95031_codec, base_addr); - /* Set the stop bit to zero */ - snd_soc_write(sn95031_codec, base_addr, value & 0xEF); - /* Index of the first free channel */ - base_addr++; - channel_index++; - } - - /* Since this is the last channel, set the stop bit - to 1 by ORing the DIE_SENSOR_CODE with 0x10 */ - snd_soc_write(sn95031_codec, base_addr, - SN95031_AUDIO_DETECT_CODE | 0x10); - - chnl_addr = SN95031_ADC_DATA_START_ADDR + 2 * channel_index; - pr_debug("mid_initialize : %x", chnl_addr); - configure_adc(sn95031_codec, 1); - return chnl_addr; -} - - -/* reads the ADC registers and gets the mic bias value in mV. */ -static unsigned int sn95031_get_mic_bias(struct snd_soc_codec *codec) -{ - u16 adc_adr = sn95031_initialize_adc(codec); - u16 adc_val1, adc_val2; - unsigned int mic_bias; - - sn95031_enable_mic_bias(codec); - - /* Enable the sound card for conversion before reading */ - snd_soc_write(codec, SN95031_ADC1CNTL3, 0x05); - /* Re-toggle the RRDATARD bit */ - snd_soc_write(codec, SN95031_ADC1CNTL3, 0x04); - - /* Read the higher bits of data */ - msleep(1000); - adc_val1 = snd_soc_read(codec, adc_adr); - adc_adr++; - adc_val2 = snd_soc_read(codec, adc_adr); - - /* Adding lower two bits to the higher bits */ - mic_bias = (adc_val1 << 2) + (adc_val2 & 3); - mic_bias = (mic_bias * SN95031_ADC_ONE_LSB_MULTIPLIER) / 1000; - pr_debug("mic bias = %dmV\n", mic_bias); - return mic_bias; -} -/*end - adc helper functions */ - -static int sn95031_read(void *ctx, unsigned int reg, unsigned int *val) -{ - u8 value = 0; - int ret; - - ret = intel_scu_ipc_ioread8(reg, &value); - if (ret == 0) - *val = value; - - return ret; -} - -static int sn95031_write(void *ctx, unsigned int reg, unsigned int value) -{ - return intel_scu_ipc_iowrite8(reg, value); -} - -static const struct regmap_config sn95031_regmap = { - .reg_read = sn95031_read, - .reg_write = sn95031_write, -}; - -static int sn95031_set_vaud_bias(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - switch (level) { - case SND_SOC_BIAS_ON: - break; - - case SND_SOC_BIAS_PREPARE: - if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) { - pr_debug("vaud_bias powering up pll\n"); - /* power up the pll */ - snd_soc_write(codec, SN95031_AUDPLLCTRL, BIT(5)); - /* enable pcm 2 */ - snd_soc_update_bits(codec, SN95031_PCM2C2, - BIT(0), BIT(0)); - } - break; - - case SND_SOC_BIAS_STANDBY: - switch (snd_soc_codec_get_bias_level(codec)) { - case SND_SOC_BIAS_OFF: - pr_debug("vaud_bias power up rail\n"); - /* power up the rail */ - snd_soc_write(codec, SN95031_VAUD, - BIT(2)|BIT(1)|BIT(0)); - msleep(1); - break; - case SND_SOC_BIAS_PREPARE: - /* turn off pcm */ - pr_debug("vaud_bias power dn pcm\n"); - snd_soc_update_bits(codec, SN95031_PCM2C2, BIT(0), 0); - snd_soc_write(codec, SN95031_AUDPLLCTRL, 0); - break; - default: - break; - } - break; - - - case SND_SOC_BIAS_OFF: - pr_debug("vaud_bias _OFF doing rail shutdown\n"); - snd_soc_write(codec, SN95031_VAUD, BIT(3)); - break; - } - - return 0; -} - -static int sn95031_vhs_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - - if (SND_SOC_DAPM_EVENT_ON(event)) { - pr_debug("VHS SND_SOC_DAPM_EVENT_ON doing rail startup now\n"); - /* power up the rail */ - snd_soc_write(codec, SN95031_VHSP, 0x3D); - snd_soc_write(codec, SN95031_VHSN, 0x3F); - msleep(1); - } else if (SND_SOC_DAPM_EVENT_OFF(event)) { - pr_debug("VHS SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n"); - snd_soc_write(codec, SN95031_VHSP, 0xC4); - snd_soc_write(codec, SN95031_VHSN, 0x04); - } - return 0; -} - -static int sn95031_vihf_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - - if (SND_SOC_DAPM_EVENT_ON(event)) { - pr_debug("VIHF SND_SOC_DAPM_EVENT_ON doing rail startup now\n"); - /* power up the rail */ - snd_soc_write(codec, SN95031_VIHF, 0x27); - msleep(1); - } else if (SND_SOC_DAPM_EVENT_OFF(event)) { - pr_debug("VIHF SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n"); - snd_soc_write(codec, SN95031_VIHF, 0x24); - } - return 0; -} - -static int sn95031_dmic12_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - unsigned int ldo = 0, clk_dir = 0, data_dir = 0; - - if (SND_SOC_DAPM_EVENT_ON(event)) { - ldo = BIT(5)|BIT(4); - clk_dir = BIT(0); - data_dir = BIT(7); - } - /* program DMIC LDO, clock and set clock */ - snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo); - snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(0), clk_dir); - snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(7), data_dir); - return 0; -} - -static int sn95031_dmic34_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - unsigned int ldo = 0, clk_dir = 0, data_dir = 0; - - if (SND_SOC_DAPM_EVENT_ON(event)) { - ldo = BIT(5)|BIT(4); - clk_dir = BIT(2); - data_dir = BIT(1); - } - /* program DMIC LDO, clock and set clock */ - snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo); - snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(2), clk_dir); - snd_soc_update_bits(codec, SN95031_DMICBUF45, BIT(1), data_dir); - return 0; -} - -static int sn95031_dmic56_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - unsigned int ldo = 0; - - if (SND_SOC_DAPM_EVENT_ON(event)) - ldo = BIT(7)|BIT(6); - - /* program DMIC LDO */ - snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(7)|BIT(6), ldo); - return 0; -} - -/* mux controls */ -static const char *sn95031_mic_texts[] = { "AMIC", "LineIn" }; - -static SOC_ENUM_SINGLE_DECL(sn95031_micl_enum, - SN95031_ADCCONFIG, 1, sn95031_mic_texts); - -static const struct snd_kcontrol_new sn95031_micl_mux_control = - SOC_DAPM_ENUM("Route", sn95031_micl_enum); - -static SOC_ENUM_SINGLE_DECL(sn95031_micr_enum, - SN95031_ADCCONFIG, 3, sn95031_mic_texts); - -static const struct snd_kcontrol_new sn95031_micr_mux_control = - SOC_DAPM_ENUM("Route", sn95031_micr_enum); - -static const char *sn95031_input_texts[] = { "DMIC1", "DMIC2", "DMIC3", - "DMIC4", "DMIC5", "DMIC6", - "ADC Left", "ADC Right" }; - -static SOC_ENUM_SINGLE_DECL(sn95031_input1_enum, - SN95031_AUDIOMUX12, 0, sn95031_input_texts); - -static const struct snd_kcontrol_new sn95031_input1_mux_control = - SOC_DAPM_ENUM("Route", sn95031_input1_enum); - -static SOC_ENUM_SINGLE_DECL(sn95031_input2_enum, - SN95031_AUDIOMUX12, 4, sn95031_input_texts); - -static const struct snd_kcontrol_new sn95031_input2_mux_control = - SOC_DAPM_ENUM("Route", sn95031_input2_enum); - -static SOC_ENUM_SINGLE_DECL(sn95031_input3_enum, - SN95031_AUDIOMUX34, 0, sn95031_input_texts); - -static const struct snd_kcontrol_new sn95031_input3_mux_control = - SOC_DAPM_ENUM("Route", sn95031_input3_enum); - -static SOC_ENUM_SINGLE_DECL(sn95031_input4_enum, - SN95031_AUDIOMUX34, 4, sn95031_input_texts); - -static const struct snd_kcontrol_new sn95031_input4_mux_control = - SOC_DAPM_ENUM("Route", sn95031_input4_enum); - -/* capture path controls */ - -static const char *sn95031_micmode_text[] = {"Single Ended", "Differential"}; - -/* 0dB to 30dB in 10dB steps */ -static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 10, 0); - -static SOC_ENUM_SINGLE_DECL(sn95031_micmode1_enum, - SN95031_MICAMP1, 1, sn95031_micmode_text); -static SOC_ENUM_SINGLE_DECL(sn95031_micmode2_enum, - SN95031_MICAMP2, 1, sn95031_micmode_text); - -static const char *sn95031_dmic_cfg_text[] = {"GPO", "DMIC"}; - -static SOC_ENUM_SINGLE_DECL(sn95031_dmic12_cfg_enum, - SN95031_DMICMUX, 0, sn95031_dmic_cfg_text); -static SOC_ENUM_SINGLE_DECL(sn95031_dmic34_cfg_enum, - SN95031_DMICMUX, 1, sn95031_dmic_cfg_text); -static SOC_ENUM_SINGLE_DECL(sn95031_dmic56_cfg_enum, - SN95031_DMICMUX, 2, sn95031_dmic_cfg_text); - -static const struct snd_kcontrol_new sn95031_snd_controls[] = { - SOC_ENUM("Mic1Mode Capture Route", sn95031_micmode1_enum), - SOC_ENUM("Mic2Mode Capture Route", sn95031_micmode2_enum), - SOC_ENUM("DMIC12 Capture Route", sn95031_dmic12_cfg_enum), - SOC_ENUM("DMIC34 Capture Route", sn95031_dmic34_cfg_enum), - SOC_ENUM("DMIC56 Capture Route", sn95031_dmic56_cfg_enum), - SOC_SINGLE_TLV("Mic1 Capture Volume", SN95031_MICAMP1, - 2, 4, 0, mic_tlv), - SOC_SINGLE_TLV("Mic2 Capture Volume", SN95031_MICAMP2, - 2, 4, 0, mic_tlv), -}; - -/* DAPM widgets */ -static const struct snd_soc_dapm_widget sn95031_dapm_widgets[] = { - - /* all end points mic, hs etc */ - SND_SOC_DAPM_OUTPUT("HPOUTL"), - SND_SOC_DAPM_OUTPUT("HPOUTR"), - SND_SOC_DAPM_OUTPUT("EPOUT"), - SND_SOC_DAPM_OUTPUT("IHFOUTL"), - SND_SOC_DAPM_OUTPUT("IHFOUTR"), - SND_SOC_DAPM_OUTPUT("LINEOUTL"), - SND_SOC_DAPM_OUTPUT("LINEOUTR"), - SND_SOC_DAPM_OUTPUT("VIB1OUT"), - SND_SOC_DAPM_OUTPUT("VIB2OUT"), - - SND_SOC_DAPM_INPUT("AMIC1"), /* headset mic */ - SND_SOC_DAPM_INPUT("AMIC2"), - SND_SOC_DAPM_INPUT("DMIC1"), - SND_SOC_DAPM_INPUT("DMIC2"), - SND_SOC_DAPM_INPUT("DMIC3"), - SND_SOC_DAPM_INPUT("DMIC4"), - SND_SOC_DAPM_INPUT("DMIC5"), - SND_SOC_DAPM_INPUT("DMIC6"), - SND_SOC_DAPM_INPUT("LINEINL"), - SND_SOC_DAPM_INPUT("LINEINR"), - - SND_SOC_DAPM_MICBIAS("AMIC1Bias", SN95031_MICBIAS, 2, 0), - SND_SOC_DAPM_MICBIAS("AMIC2Bias", SN95031_MICBIAS, 3, 0), - SND_SOC_DAPM_MICBIAS("DMIC12Bias", SN95031_DMICMUX, 3, 0), - SND_SOC_DAPM_MICBIAS("DMIC34Bias", SN95031_DMICMUX, 4, 0), - SND_SOC_DAPM_MICBIAS("DMIC56Bias", SN95031_DMICMUX, 5, 0), - - SND_SOC_DAPM_SUPPLY("DMIC12supply", SN95031_DMICLK, 0, 0, - sn95031_dmic12_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("DMIC34supply", SN95031_DMICLK, 1, 0, - sn95031_dmic34_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("DMIC56supply", SN95031_DMICLK, 2, 0, - sn95031_dmic56_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - - SND_SOC_DAPM_AIF_OUT("PCM_Out", "Capture", 0, - SND_SOC_NOPM, 0, 0), - - SND_SOC_DAPM_SUPPLY("Headset Rail", SND_SOC_NOPM, 0, 0, - sn95031_vhs_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("Speaker Rail", SND_SOC_NOPM, 0, 0, - sn95031_vihf_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - - /* playback path driver enables */ - SND_SOC_DAPM_PGA("Headset Left Playback", - SN95031_DRIVEREN, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("Headset Right Playback", - SN95031_DRIVEREN, 1, 0, NULL, 0), - SND_SOC_DAPM_PGA("Speaker Left Playback", - SN95031_DRIVEREN, 2, 0, NULL, 0), - SND_SOC_DAPM_PGA("Speaker Right Playback", - SN95031_DRIVEREN, 3, 0, NULL, 0), - SND_SOC_DAPM_PGA("Vibra1 Playback", - SN95031_DRIVEREN, 4, 0, NULL, 0), - SND_SOC_DAPM_PGA("Vibra2 Playback", - SN95031_DRIVEREN, 5, 0, NULL, 0), - SND_SOC_DAPM_PGA("Earpiece Playback", - SN95031_DRIVEREN, 6, 0, NULL, 0), - SND_SOC_DAPM_PGA("Lineout Left Playback", - SN95031_LOCTL, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("Lineout Right Playback", - SN95031_LOCTL, 4, 0, NULL, 0), - - /* playback path filter enable */ - SND_SOC_DAPM_PGA("Headset Left Filter", - SN95031_HSEPRXCTRL, 4, 0, NULL, 0), - SND_SOC_DAPM_PGA("Headset Right Filter", - SN95031_HSEPRXCTRL, 5, 0, NULL, 0), - SND_SOC_DAPM_PGA("Speaker Left Filter", - SN95031_IHFRXCTRL, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("Speaker Right Filter", - SN95031_IHFRXCTRL, 1, 0, NULL, 0), - - /* DACs */ - SND_SOC_DAPM_DAC("HSDAC Left", "Headset", - SN95031_DACCONFIG, 0, 0), - SND_SOC_DAPM_DAC("HSDAC Right", "Headset", - SN95031_DACCONFIG, 1, 0), - SND_SOC_DAPM_DAC("IHFDAC Left", "Speaker", - SN95031_DACCONFIG, 2, 0), - SND_SOC_DAPM_DAC("IHFDAC Right", "Speaker", - SN95031_DACCONFIG, 3, 0), - SND_SOC_DAPM_DAC("Vibra1 DAC", "Vibra1", - SN95031_VIB1C5, 1, 0), - SND_SOC_DAPM_DAC("Vibra2 DAC", "Vibra2", - SN95031_VIB2C5, 1, 0), - - /* capture widgets */ - SND_SOC_DAPM_PGA("LineIn Enable Left", SN95031_MICAMP1, - 7, 0, NULL, 0), - SND_SOC_DAPM_PGA("LineIn Enable Right", SN95031_MICAMP2, - 7, 0, NULL, 0), - - SND_SOC_DAPM_PGA("MIC1 Enable", SN95031_MICAMP1, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("MIC2 Enable", SN95031_MICAMP2, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("TX1 Enable", SN95031_AUDIOTXEN, 2, 0, NULL, 0), - SND_SOC_DAPM_PGA("TX2 Enable", SN95031_AUDIOTXEN, 3, 0, NULL, 0), - SND_SOC_DAPM_PGA("TX3 Enable", SN95031_AUDIOTXEN, 4, 0, NULL, 0), - SND_SOC_DAPM_PGA("TX4 Enable", SN95031_AUDIOTXEN, 5, 0, NULL, 0), - - /* ADC have null stream as they will be turned ON by TX path */ - SND_SOC_DAPM_ADC("ADC Left", NULL, - SN95031_ADCCONFIG, 0, 0), - SND_SOC_DAPM_ADC("ADC Right", NULL, - SN95031_ADCCONFIG, 2, 0), - - SND_SOC_DAPM_MUX("Mic_InputL Capture Route", - SND_SOC_NOPM, 0, 0, &sn95031_micl_mux_control), - SND_SOC_DAPM_MUX("Mic_InputR Capture Route", - SND_SOC_NOPM, 0, 0, &sn95031_micr_mux_control), - - SND_SOC_DAPM_MUX("Txpath1 Capture Route", - SND_SOC_NOPM, 0, 0, &sn95031_input1_mux_control), - SND_SOC_DAPM_MUX("Txpath2 Capture Route", - SND_SOC_NOPM, 0, 0, &sn95031_input2_mux_control), - SND_SOC_DAPM_MUX("Txpath3 Capture Route", - SND_SOC_NOPM, 0, 0, &sn95031_input3_mux_control), - SND_SOC_DAPM_MUX("Txpath4 Capture Route", - SND_SOC_NOPM, 0, 0, &sn95031_input4_mux_control), - -}; - -static const struct snd_soc_dapm_route sn95031_audio_map[] = { - /* headset and earpiece map */ - { "HPOUTL", NULL, "Headset Rail"}, - { "HPOUTR", NULL, "Headset Rail"}, - { "HPOUTL", NULL, "Headset Left Playback" }, - { "HPOUTR", NULL, "Headset Right Playback" }, - { "EPOUT", NULL, "Earpiece Playback" }, - { "Headset Left Playback", NULL, "Headset Left Filter"}, - { "Headset Right Playback", NULL, "Headset Right Filter"}, - { "Earpiece Playback", NULL, "Headset Left Filter"}, - { "Headset Left Filter", NULL, "HSDAC Left"}, - { "Headset Right Filter", NULL, "HSDAC Right"}, - - /* speaker map */ - { "IHFOUTL", NULL, "Speaker Rail"}, - { "IHFOUTR", NULL, "Speaker Rail"}, - { "IHFOUTL", NULL, "Speaker Left Playback"}, - { "IHFOUTR", NULL, "Speaker Right Playback"}, - { "Speaker Left Playback", NULL, "Speaker Left Filter"}, - { "Speaker Right Playback", NULL, "Speaker Right Filter"}, - { "Speaker Left Filter", NULL, "IHFDAC Left"}, - { "Speaker Right Filter", NULL, "IHFDAC Right"}, - - /* vibra map */ - { "VIB1OUT", NULL, "Vibra1 Playback"}, - { "Vibra1 Playback", NULL, "Vibra1 DAC"}, - - { "VIB2OUT", NULL, "Vibra2 Playback"}, - { "Vibra2 Playback", NULL, "Vibra2 DAC"}, - - /* lineout */ - { "LINEOUTL", NULL, "Lineout Left Playback"}, - { "LINEOUTR", NULL, "Lineout Right Playback"}, - { "Lineout Left Playback", NULL, "Headset Left Filter"}, - { "Lineout Left Playback", NULL, "Speaker Left Filter"}, - { "Lineout Left Playback", NULL, "Vibra1 DAC"}, - { "Lineout Right Playback", NULL, "Headset Right Filter"}, - { "Lineout Right Playback", NULL, "Speaker Right Filter"}, - { "Lineout Right Playback", NULL, "Vibra2 DAC"}, - - /* Headset (AMIC1) mic */ - { "AMIC1Bias", NULL, "AMIC1"}, - { "MIC1 Enable", NULL, "AMIC1Bias"}, - { "Mic_InputL Capture Route", "AMIC", "MIC1 Enable"}, - - /* AMIC2 */ - { "AMIC2Bias", NULL, "AMIC2"}, - { "MIC2 Enable", NULL, "AMIC2Bias"}, - { "Mic_InputR Capture Route", "AMIC", "MIC2 Enable"}, - - - /* Linein */ - { "LineIn Enable Left", NULL, "LINEINL"}, - { "LineIn Enable Right", NULL, "LINEINR"}, - { "Mic_InputL Capture Route", "LineIn", "LineIn Enable Left"}, - { "Mic_InputR Capture Route", "LineIn", "LineIn Enable Right"}, - - /* ADC connection */ - { "ADC Left", NULL, "Mic_InputL Capture Route"}, - { "ADC Right", NULL, "Mic_InputR Capture Route"}, - - /*DMIC connections */ - { "DMIC1", NULL, "DMIC12supply"}, - { "DMIC2", NULL, "DMIC12supply"}, - { "DMIC3", NULL, "DMIC34supply"}, - { "DMIC4", NULL, "DMIC34supply"}, - { "DMIC5", NULL, "DMIC56supply"}, - { "DMIC6", NULL, "DMIC56supply"}, - - { "DMIC12Bias", NULL, "DMIC1"}, - { "DMIC12Bias", NULL, "DMIC2"}, - { "DMIC34Bias", NULL, "DMIC3"}, - { "DMIC34Bias", NULL, "DMIC4"}, - { "DMIC56Bias", NULL, "DMIC5"}, - { "DMIC56Bias", NULL, "DMIC6"}, - - /*TX path inputs*/ - { "Txpath1 Capture Route", "ADC Left", "ADC Left"}, - { "Txpath2 Capture Route", "ADC Left", "ADC Left"}, - { "Txpath3 Capture Route", "ADC Left", "ADC Left"}, - { "Txpath4 Capture Route", "ADC Left", "ADC Left"}, - { "Txpath1 Capture Route", "ADC Right", "ADC Right"}, - { "Txpath2 Capture Route", "ADC Right", "ADC Right"}, - { "Txpath3 Capture Route", "ADC Right", "ADC Right"}, - { "Txpath4 Capture Route", "ADC Right", "ADC Right"}, - { "Txpath1 Capture Route", "DMIC1", "DMIC1"}, - { "Txpath2 Capture Route", "DMIC1", "DMIC1"}, - { "Txpath3 Capture Route", "DMIC1", "DMIC1"}, - { "Txpath4 Capture Route", "DMIC1", "DMIC1"}, - { "Txpath1 Capture Route", "DMIC2", "DMIC2"}, - { "Txpath2 Capture Route", "DMIC2", "DMIC2"}, - { "Txpath3 Capture Route", "DMIC2", "DMIC2"}, - { "Txpath4 Capture Route", "DMIC2", "DMIC2"}, - { "Txpath1 Capture Route", "DMIC3", "DMIC3"}, - { "Txpath2 Capture Route", "DMIC3", "DMIC3"}, - { "Txpath3 Capture Route", "DMIC3", "DMIC3"}, - { "Txpath4 Capture Route", "DMIC3", "DMIC3"}, - { "Txpath1 Capture Route", "DMIC4", "DMIC4"}, - { "Txpath2 Capture Route", "DMIC4", "DMIC4"}, - { "Txpath3 Capture Route", "DMIC4", "DMIC4"}, - { "Txpath4 Capture Route", "DMIC4", "DMIC4"}, - { "Txpath1 Capture Route", "DMIC5", "DMIC5"}, - { "Txpath2 Capture Route", "DMIC5", "DMIC5"}, - { "Txpath3 Capture Route", "DMIC5", "DMIC5"}, - { "Txpath4 Capture Route", "DMIC5", "DMIC5"}, - { "Txpath1 Capture Route", "DMIC6", "DMIC6"}, - { "Txpath2 Capture Route", "DMIC6", "DMIC6"}, - { "Txpath3 Capture Route", "DMIC6", "DMIC6"}, - { "Txpath4 Capture Route", "DMIC6", "DMIC6"}, - - /* tx path */ - { "TX1 Enable", NULL, "Txpath1 Capture Route"}, - { "TX2 Enable", NULL, "Txpath2 Capture Route"}, - { "TX3 Enable", NULL, "Txpath3 Capture Route"}, - { "TX4 Enable", NULL, "Txpath4 Capture Route"}, - { "PCM_Out", NULL, "TX1 Enable"}, - { "PCM_Out", NULL, "TX2 Enable"}, - { "PCM_Out", NULL, "TX3 Enable"}, - { "PCM_Out", NULL, "TX4 Enable"}, - -}; - -/* speaker and headset mutes, for audio pops and clicks */ -static int sn95031_pcm_hs_mute(struct snd_soc_dai *dai, int mute) -{ - snd_soc_update_bits(dai->codec, - SN95031_HSLVOLCTRL, BIT(7), (!mute << 7)); - snd_soc_update_bits(dai->codec, - SN95031_HSRVOLCTRL, BIT(7), (!mute << 7)); - return 0; -} - -static int sn95031_pcm_spkr_mute(struct snd_soc_dai *dai, int mute) -{ - snd_soc_update_bits(dai->codec, - SN95031_IHFLVOLCTRL, BIT(7), (!mute << 7)); - snd_soc_update_bits(dai->codec, - SN95031_IHFRVOLCTRL, BIT(7), (!mute << 7)); - return 0; -} - -static int sn95031_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) -{ - unsigned int format, rate; - - switch (params_width(params)) { - case 16: - format = BIT(4)|BIT(5); - break; - - case 24: - format = 0; - break; - default: - return -EINVAL; - } - snd_soc_update_bits(dai->codec, SN95031_PCM2C2, - BIT(4)|BIT(5), format); - - switch (params_rate(params)) { - case 48000: - pr_debug("RATE_48000\n"); - rate = 0; - break; - - case 44100: - pr_debug("RATE_44100\n"); - rate = BIT(7); - break; - - default: - pr_err("ERR rate %d\n", params_rate(params)); - return -EINVAL; - } - snd_soc_update_bits(dai->codec, SN95031_PCM1C1, BIT(7), rate); - - return 0; -} - -/* Codec DAI section */ -static const struct snd_soc_dai_ops sn95031_headset_dai_ops = { - .digital_mute = sn95031_pcm_hs_mute, - .hw_params = sn95031_pcm_hw_params, -}; - -static const struct snd_soc_dai_ops sn95031_speaker_dai_ops = { - .digital_mute = sn95031_pcm_spkr_mute, - .hw_params = sn95031_pcm_hw_params, -}; - -static const struct snd_soc_dai_ops sn95031_vib1_dai_ops = { - .hw_params = sn95031_pcm_hw_params, -}; - -static const struct snd_soc_dai_ops sn95031_vib2_dai_ops = { - .hw_params = sn95031_pcm_hw_params, -}; - -static struct snd_soc_dai_driver sn95031_dais[] = { -{ - .name = "SN95031 Headset", - .playback = { - .stream_name = "Headset", - .channels_min = 2, - .channels_max = 2, - .rates = SN95031_RATES, - .formats = SN95031_FORMATS, - }, - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 5, - .rates = SN95031_RATES, - .formats = SN95031_FORMATS, - }, - .ops = &sn95031_headset_dai_ops, -}, -{ .name = "SN95031 Speaker", - .playback = { - .stream_name = "Speaker", - .channels_min = 2, - .channels_max = 2, - .rates = SN95031_RATES, - .formats = SN95031_FORMATS, - }, - .ops = &sn95031_speaker_dai_ops, -}, -{ .name = "SN95031 Vibra1", - .playback = { - .stream_name = "Vibra1", - .channels_min = 1, - .channels_max = 1, - .rates = SN95031_RATES, - .formats = SN95031_FORMATS, - }, - .ops = &sn95031_vib1_dai_ops, -}, -{ .name = "SN95031 Vibra2", - .playback = { - .stream_name = "Vibra2", - .channels_min = 1, - .channels_max = 1, - .rates = SN95031_RATES, - .formats = SN95031_FORMATS, - }, - .ops = &sn95031_vib2_dai_ops, -}, -}; - -static inline void sn95031_disable_jack_btn(struct snd_soc_codec *codec) -{ - snd_soc_write(codec, SN95031_BTNCTRL2, 0x00); -} - -static inline void sn95031_enable_jack_btn(struct snd_soc_codec *codec) -{ - snd_soc_write(codec, SN95031_BTNCTRL1, 0x77); - snd_soc_write(codec, SN95031_BTNCTRL2, 0x01); -} - -static int sn95031_get_headset_state(struct snd_soc_codec *codec, - struct snd_soc_jack *mfld_jack) -{ - int micbias = sn95031_get_mic_bias(codec); - - int jack_type = snd_soc_jack_get_type(mfld_jack, micbias); - - pr_debug("jack type detected = %d\n", jack_type); - if (jack_type == SND_JACK_HEADSET) - sn95031_enable_jack_btn(codec); - return jack_type; -} - -void sn95031_jack_detection(struct snd_soc_codec *codec, - struct mfld_jack_data *jack_data) -{ - unsigned int status; - unsigned int mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_HEADSET; - - pr_debug("interrupt id read in sram = 0x%x\n", jack_data->intr_id); - if (jack_data->intr_id & 0x1) { - pr_debug("short_push detected\n"); - status = SND_JACK_HEADSET | SND_JACK_BTN_0; - } else if (jack_data->intr_id & 0x2) { - pr_debug("long_push detected\n"); - status = SND_JACK_HEADSET | SND_JACK_BTN_1; - } else if (jack_data->intr_id & 0x4) { - pr_debug("headset or headphones inserted\n"); - status = sn95031_get_headset_state(codec, jack_data->mfld_jack); - } else if (jack_data->intr_id & 0x8) { - pr_debug("headset or headphones removed\n"); - status = 0; - sn95031_disable_jack_btn(codec); - } else { - pr_err("unidentified interrupt\n"); - return; - } - - snd_soc_jack_report(jack_data->mfld_jack, status, mask); - /*button pressed and released so we send explicit button release */ - if ((status & SND_JACK_BTN_0) | (status & SND_JACK_BTN_1)) - snd_soc_jack_report(jack_data->mfld_jack, - SND_JACK_HEADSET, mask); -} -EXPORT_SYMBOL_GPL(sn95031_jack_detection); - -/* codec registration */ -static int sn95031_codec_probe(struct snd_soc_codec *codec) -{ - pr_debug("codec_probe called\n"); - - /* PCM interface config - * This sets the pcm rx slot conguration to max 6 slots - * for max 4 dais (2 stereo and 2 mono) - */ - snd_soc_write(codec, SN95031_PCM2RXSLOT01, 0x10); - snd_soc_write(codec, SN95031_PCM2RXSLOT23, 0x32); - snd_soc_write(codec, SN95031_PCM2RXSLOT45, 0x54); - snd_soc_write(codec, SN95031_PCM2TXSLOT01, 0x10); - snd_soc_write(codec, SN95031_PCM2TXSLOT23, 0x32); - /* pcm port setting - * This sets the pcm port to slave and clock at 19.2Mhz which - * can support 6slots, sampling rate set per stream in hw-params - */ - snd_soc_write(codec, SN95031_PCM1C1, 0x00); - snd_soc_write(codec, SN95031_PCM2C1, 0x01); - snd_soc_write(codec, SN95031_PCM2C2, 0x0A); - snd_soc_write(codec, SN95031_HSMIXER, BIT(0)|BIT(4)); - /* vendor vibra workround, the vibras are muted by - * custom register so unmute them - */ - snd_soc_write(codec, SN95031_SSR5, 0x80); - snd_soc_write(codec, SN95031_SSR6, 0x80); - snd_soc_write(codec, SN95031_VIB1C5, 0x00); - snd_soc_write(codec, SN95031_VIB2C5, 0x00); - /* configure vibras for pcm port */ - snd_soc_write(codec, SN95031_VIB1C3, 0x00); - snd_soc_write(codec, SN95031_VIB2C3, 0x00); - - /* soft mute ramp time */ - snd_soc_write(codec, SN95031_SOFTMUTE, 0x3); - /* fix the initial volume at 1dB, - * default in +9dB, - * 1dB give optimal swing on DAC, amps - */ - snd_soc_write(codec, SN95031_HSLVOLCTRL, 0x08); - snd_soc_write(codec, SN95031_HSRVOLCTRL, 0x08); - snd_soc_write(codec, SN95031_IHFLVOLCTRL, 0x08); - snd_soc_write(codec, SN95031_IHFRVOLCTRL, 0x08); - /* dac mode and lineout workaround */ - snd_soc_write(codec, SN95031_SSR2, 0x10); - snd_soc_write(codec, SN95031_SSR3, 0x40); - - return 0; -} - -static const struct snd_soc_codec_driver sn95031_codec = { - .probe = sn95031_codec_probe, - .set_bias_level = sn95031_set_vaud_bias, - .idle_bias_off = true, - - .component_driver = { - .controls = sn95031_snd_controls, - .num_controls = ARRAY_SIZE(sn95031_snd_controls), - .dapm_widgets = sn95031_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(sn95031_dapm_widgets), - .dapm_routes = sn95031_audio_map, - .num_dapm_routes = ARRAY_SIZE(sn95031_audio_map), - }, -}; - -static int sn95031_device_probe(struct platform_device *pdev) -{ - struct regmap *regmap; - - pr_debug("codec device probe called for %s\n", dev_name(&pdev->dev)); - - regmap = devm_regmap_init(&pdev->dev, NULL, NULL, &sn95031_regmap); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - return snd_soc_register_codec(&pdev->dev, &sn95031_codec, - sn95031_dais, ARRAY_SIZE(sn95031_dais)); -} - -static int sn95031_device_remove(struct platform_device *pdev) -{ - pr_debug("codec device remove called\n"); - snd_soc_unregister_codec(&pdev->dev); - return 0; -} - -static struct platform_driver sn95031_codec_driver = { - .driver = { - .name = "sn95031", - }, - .probe = sn95031_device_probe, - .remove = sn95031_device_remove, -}; - -module_platform_driver(sn95031_codec_driver); - -MODULE_DESCRIPTION("ASoC TI SN95031 codec driver"); -MODULE_AUTHOR("Vinod Koul "); -MODULE_AUTHOR("Harsha Priya "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:sn95031"); diff --git a/sound/soc/codecs/sn95031.h b/sound/soc/codecs/sn95031.h deleted file mode 100644 index 7651fe4e6a45..000000000000 --- a/sound/soc/codecs/sn95031.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * sn95031.h - TI sn95031 Codec driver - * - * Copyright (C) 2010 Intel Corp - * Author: Vinod Koul - * Author: Harsha Priya - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * - */ -#ifndef _SN95031_H -#define _SN95031_H - -/*register map*/ -#define SN95031_VAUD 0xDB -#define SN95031_VHSP 0xDC -#define SN95031_VHSN 0xDD -#define SN95031_VIHF 0xC9 - -#define SN95031_AUDPLLCTRL 0x240 -#define SN95031_DMICBUF0123 0x241 -#define SN95031_DMICBUF45 0x242 -#define SN95031_DMICGPO 0x244 -#define SN95031_DMICMUX 0x245 -#define SN95031_DMICLK 0x246 -#define SN95031_MICBIAS 0x247 -#define SN95031_ADCCONFIG 0x248 -#define SN95031_MICAMP1 0x249 -#define SN95031_MICAMP2 0x24A -#define SN95031_NOISEMUX 0x24B -#define SN95031_AUDIOMUX12 0x24C -#define SN95031_AUDIOMUX34 0x24D -#define SN95031_AUDIOSINC 0x24E -#define SN95031_AUDIOTXEN 0x24F -#define SN95031_HSEPRXCTRL 0x250 -#define SN95031_IHFRXCTRL 0x251 -#define SN95031_HSMIXER 0x256 -#define SN95031_DACCONFIG 0x257 -#define SN95031_SOFTMUTE 0x258 -#define SN95031_HSLVOLCTRL 0x259 -#define SN95031_HSRVOLCTRL 0x25A -#define SN95031_IHFLVOLCTRL 0x25B -#define SN95031_IHFRVOLCTRL 0x25C -#define SN95031_DRIVEREN 0x25D -#define SN95031_LOCTL 0x25E -#define SN95031_VIB1C1 0x25F -#define SN95031_VIB1C2 0x260 -#define SN95031_VIB1C3 0x261 -#define SN95031_VIB1SPIPCM1 0x262 -#define SN95031_VIB1SPIPCM2 0x263 -#define SN95031_VIB1C5 0x264 -#define SN95031_VIB2C1 0x265 -#define SN95031_VIB2C2 0x266 -#define SN95031_VIB2C3 0x267 -#define SN95031_VIB2SPIPCM1 0x268 -#define SN95031_VIB2SPIPCM2 0x269 -#define SN95031_VIB2C5 0x26A -#define SN95031_BTNCTRL1 0x26B -#define SN95031_BTNCTRL2 0x26C -#define SN95031_PCM1TXSLOT01 0x26D -#define SN95031_PCM1TXSLOT23 0x26E -#define SN95031_PCM1TXSLOT45 0x26F -#define SN95031_PCM1RXSLOT0_3 0x270 -#define SN95031_PCM1RXSLOT45 0x271 -#define SN95031_PCM2TXSLOT01 0x272 -#define SN95031_PCM2TXSLOT23 0x273 -#define SN95031_PCM2TXSLOT45 0x274 -#define SN95031_PCM2RXSLOT01 0x275 -#define SN95031_PCM2RXSLOT23 0x276 -#define SN95031_PCM2RXSLOT45 0x277 -#define SN95031_PCM1C1 0x278 -#define SN95031_PCM1C2 0x279 -#define SN95031_PCM1C3 0x27A -#define SN95031_PCM2C1 0x27B -#define SN95031_PCM2C2 0x27C -/*end codec register defn*/ - -/*vendor defn these are not part of avp*/ -#define SN95031_SSR2 0x381 -#define SN95031_SSR3 0x382 -#define SN95031_SSR5 0x384 -#define SN95031_SSR6 0x385 - -/* ADC registers */ - -#define SN95031_ADC1CNTL1 0x1C0 -#define SN95031_ADC_ENBL 0x10 -#define SN95031_ADC_START 0x08 -#define SN95031_ADC1CNTL3 0x1C2 -#define SN95031_ADCTHERM_ENBL 0x04 -#define SN95031_ADCRRDATA_ENBL 0x05 -#define SN95031_STOPBIT_MASK 16 -#define SN95031_ADCTHERM_MASK 4 -#define SN95031_ADC_CHANLS_MAX 15 /* Number of ADC channels */ -#define SN95031_ADC_LOOP_MAX (SN95031_ADC_CHANLS_MAX - 1) -#define SN95031_ADC_NO_LOOP 0x07 -#define SN95031_AUDIO_GPIO_CTRL 0x070 - -/* ADC channel code values */ -#define SN95031_AUDIO_DETECT_CODE 0x06 - -/* ADC base addresses */ -#define SN95031_ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */ -#define SN95031_ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */ -/* multipier to convert to mV */ -#define SN95031_ADC_ONE_LSB_MULTIPLIER 2346 - - -struct mfld_jack_data { - int intr_id; - int micbias_vol; - struct snd_soc_jack *mfld_jack; -}; - -extern void sn95031_jack_detection(struct snd_soc_codec *codec, - struct mfld_jack_data *jack_data); - -#endif -- cgit v1.2.3 From 11aa2d9613c9523f8f78863bdfc7d79b37afcbbe Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 5 Jan 2018 17:00:51 +0800 Subject: ASoC: mt8173: remove unnecessary micbias widget in route The micbias1/2 are connected to route as SUPPLY usage. It was not take effect since they were MICBIAS type. To keep the same register settings, we have to remove it once the micbias1/2 widget is converted to SUPPLY type. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c | 2 -- sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c | 2 -- sound/soc/mediatek/mt8173/mt8173-rt5650.c | 2 -- 3 files changed, 6 deletions(-) diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index 99c15219dbc8..5a9a5482976e 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -37,8 +37,6 @@ static const struct snd_soc_dapm_route mt8173_rt5650_rt5514_routes[] = { {"Sub DMIC1R", NULL, "Int Mic"}, {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, - {"Headset Mic", NULL, "micbias1"}, - {"Headset Mic", NULL, "micbias2"}, {"IN1P", NULL, "Headset Mic"}, {"IN1N", NULL, "Headset Mic"}, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 42de84ca8c84..b7248085ca04 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -40,8 +40,6 @@ static const struct snd_soc_dapm_route mt8173_rt5650_rt5676_routes[] = { {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, {"Headphone", NULL, "Sub AIF2TX"}, /* IF2 ADC to 5650 */ - {"Headset Mic", NULL, "micbias1"}, - {"Headset Mic", NULL, "micbias2"}, {"IN1P", NULL, "Headset Mic"}, {"IN1N", NULL, "Headset Mic"}, {"Sub AIF2RX", NULL, "Headset Mic"}, /* IF2 DAC from 5650 */ diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index e69c141d8ed4..40ebefd625c1 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -51,8 +51,6 @@ static const struct snd_soc_dapm_route mt8173_rt5650_routes[] = { {"DMIC R1", NULL, "Int Mic"}, {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, - {"Headset Mic", NULL, "micbias1"}, - {"Headset Mic", NULL, "micbias2"}, {"IN1P", NULL, "Headset Mic"}, {"IN1N", NULL, "Headset Mic"}, }; -- cgit v1.2.3 From 9ae148f80a96a91b636ab0b57d24d4440b919817 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Wed, 10 Jan 2018 23:23:05 +0800 Subject: IIO: ADC: stm32_dfsdm_stop_filter() can be static Fixes: e2e6771c6462 ("IIO: ADC: add STM32 DFSDM sigma delta ADC support") Signed-off-by: Fengguang Wu Acked-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- drivers/iio/adc/stm32-dfsdm-adc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index b03ca3f94331..e628d04d5c77 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -254,7 +254,7 @@ static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm, DFSDM_CR1_RSWSTART(1)); } -void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, unsigned int fl_id) +static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, unsigned int fl_id) { /* Disable conversion */ regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id), @@ -296,9 +296,9 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm *dfsdm, DFSDM_CR1_RSYNC(fl->sync_mode)); } -int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, - struct iio_dev *indio_dev, - struct iio_chan_spec *ch) +static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, + struct iio_dev *indio_dev, + struct iio_chan_spec *ch) { struct stm32_dfsdm_channel *df_ch; const char *of_str; -- cgit v1.2.3 From 1783c9d7cb7bc3181b9271665959b87280d98d8e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 10 Jan 2018 17:34:45 +0100 Subject: ASoC: ux500: add MODULE_LICENSE tag This adds MODULE_LICENSE/AUTHOR/DESCRIPTION tags to the ux500 platform drivers, to avoid these build warnings: WARNING: modpost: missing MODULE_LICENSE() in sound/soc/ux500/snd-soc-ux500-plat-dma.o WARNING: modpost: missing MODULE_LICENSE() in sound/soc/ux500/snd-soc-ux500-mach-mop500.o The company no longer exists, so the email addresses of the authors don't work any more, but I've added them anyway for consistency. Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/ux500/mop500.c | 4 ++++ sound/soc/ux500/ux500_pcm.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c index 070a6880980e..c60a57797640 100644 --- a/sound/soc/ux500/mop500.c +++ b/sound/soc/ux500/mop500.c @@ -163,3 +163,7 @@ static struct platform_driver snd_soc_mop500_driver = { }; module_platform_driver(snd_soc_mop500_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ASoC MOP500 board driver"); +MODULE_AUTHOR("Ola Lilja"); diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c index f12c01dddc8d..d35ba7700f46 100644 --- a/sound/soc/ux500/ux500_pcm.c +++ b/sound/soc/ux500/ux500_pcm.c @@ -165,3 +165,8 @@ int ux500_pcm_unregister_platform(struct platform_device *pdev) return 0; } EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform); + +MODULE_AUTHOR("Ola Lilja"); +MODULE_AUTHOR("Roger Nilsson"); +MODULE_DESCRIPTION("ASoC UX500 driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 9cee7972bd0c69bc05d2e2f09bccd81cc439328b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 11 Jan 2018 11:33:26 +0100 Subject: ASoC: stm32: select IIO_BUFFER The new stm32_adfsdm driver has incomplete dependencies as shown by Kconfig: warning: (SND_SOC_STM32_DFSDM && LMP91000) selects IIO_BUFFER_CB which has unmet direct dependencies (IIO && IIO_BUFFER) sound/soc/stm/stm32_adfsdm.o: In function `stm32_adfsdm_trigger': stm32_adfsdm.c:(.text+0x8c): undefined reference to `stm32_dfsdm_get_buff_cb' stm32_adfsdm.c:(.text+0x9c): undefined reference to `stm32_dfsdm_release_buff_cb' This makes the dependency on SND_SOC_STM32_DFSDM unconditional, so we can always resolve the stm32_dfsdm_get_buff_cb/stm32_dfsdm_release_buff_cb symbols and get the implied IIO_BUFFER dependency. compile-testing on other platforms is still possible as long as that IIO driver is there. Fixes: 55da094824c4 ("ASoC: stm32: add DFSDM DAI support") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/stm/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index a78f7700d489..3ad881fc40a1 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -30,8 +30,9 @@ config SND_SOC_STM32_SPDIFRX config SND_SOC_STM32_DFSDM tristate "SoC Audio support for STM32 DFSDM" - depends on (ARCH_STM32 && OF && STM32_DFSDM_ADC) || COMPILE_TEST + depends on ARCH_STM32 || COMPILE_TEST depends on SND_SOC + depends on STM32_DFSDM_ADC select SND_SOC_GENERIC_DMAENGINE_PCM select SND_SOC_DMIC select IIO_BUFFER_CB -- cgit v1.2.3 From 6dee6722c6065f4850eab98c2b7b9f4a08a35813 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 11 Jan 2018 11:11:51 +0000 Subject: ASoC: stm32: fix a typo in stm32_adfsdm_probe() Fix a typo, we should return PTR_ERR(priv->iio_cb) instead of PTR_ERR(priv->iio_ch). Fixes: 55da094824c4 ("ASoC: stm32: add DFSDM DAI support") Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/stm/stm32_adfsdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c index af50891983c6..7306e3eca9e1 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c @@ -320,7 +320,7 @@ static int stm32_adfsdm_probe(struct platform_device *pdev) priv->iio_cb = iio_channel_get_all_cb(&pdev->dev, NULL, NULL); if (IS_ERR(priv->iio_cb)) - return PTR_ERR(priv->iio_ch); + return PTR_ERR(priv->iio_cb); ret = devm_snd_soc_register_platform(&pdev->dev, &stm32_adfsdm_soc_platform); -- cgit v1.2.3 From 2353758bc2d427809f5feb15f046ded91c60afef Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 11 Jan 2018 11:34:46 +0100 Subject: IIO: ADC: stm32-dfsdm: avoid unused-variable warning Building with CONFIG_OF disabled produces a compiler warning: drivers/iio/adc/stm32-dfsdm-core.c: In function 'stm32_dfsdm_probe': drivers/iio/adc/stm32-dfsdm-core.c:245:22: error: unused variable 'pnode' [-Werror=unused-variable] This removes the variable and open-codes it in the only place it gets used to avoid that warning. Fixes: bed73904e76f ("IIO: ADC: add stm32 DFSDM core support") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- drivers/iio/adc/stm32-dfsdm-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index 72427414db7f..6cd655f8239b 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -242,7 +242,6 @@ MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match); static int stm32_dfsdm_probe(struct platform_device *pdev) { struct dfsdm_priv *priv; - struct device_node *pnode = pdev->dev.of_node; const struct of_device_id *of_id; const struct stm32_dfsdm_dev_data *dev_data; struct stm32_dfsdm *dfsdm; @@ -254,7 +253,7 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) priv->pdev = pdev; - of_id = of_match_node(stm32_dfsdm_of_match, pnode); + of_id = of_match_node(stm32_dfsdm_of_match, pdev->dev.of_node); if (!of_id->data) { dev_err(&pdev->dev, "Data associated to device is missing\n"); return -EINVAL; -- cgit v1.2.3 From 25140717414c319bcc44b5aac39357a52d0bc8e0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 11 Jan 2018 11:34:46 +0100 Subject: IIO: ADC: stm32-dfsdm: avoid unused-variable warning Building with CONFIG_OF disabled produces a compiler warning: drivers/iio/adc/stm32-dfsdm-core.c: In function 'stm32_dfsdm_probe': drivers/iio/adc/stm32-dfsdm-core.c:245:22: error: unused variable 'pnode' [-Werror=unused-variable] This removes the variable and open-codes it in the only place it gets used to avoid that warning. Fixes: bed73904e76f ("IIO: ADC: add stm32 DFSDM core support") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- drivers/iio/adc/stm32-dfsdm-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index 72427414db7f..6cd655f8239b 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -242,7 +242,6 @@ MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match); static int stm32_dfsdm_probe(struct platform_device *pdev) { struct dfsdm_priv *priv; - struct device_node *pnode = pdev->dev.of_node; const struct of_device_id *of_id; const struct stm32_dfsdm_dev_data *dev_data; struct stm32_dfsdm *dfsdm; @@ -254,7 +253,7 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) priv->pdev = pdev; - of_id = of_match_node(stm32_dfsdm_of_match, pnode); + of_id = of_match_node(stm32_dfsdm_of_match, pdev->dev.of_node); if (!of_id->data) { dev_err(&pdev->dev, "Data associated to device is missing\n"); return -EINVAL; -- cgit v1.2.3 From d5ff18bcd4b5e66396eab7e8271172157ee1253e Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 11 Jan 2018 11:12:41 +0000 Subject: IIO: ADC: fix return value check in stm32_dfsdm_adc_probe() In case of error, the function devm_iio_device_alloc() returns NULL pointer not ERR_PTR(). The IS_ERR() test in the return value check should be replaced with NULL test. Fixes: e2e6771c6462 ("IIO: ADC: add STM32 DFSDM sigma delta ADC support") Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- drivers/iio/adc/stm32-dfsdm-adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index e628d04d5c77..5e871404f565 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -1100,9 +1100,9 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) dev_data = (const struct stm32_dfsdm_dev_data *)of_id->data; iio = devm_iio_device_alloc(dev, sizeof(*adc)); - if (IS_ERR(iio)) { + if (!iio) { dev_err(dev, "%s: Failed to allocate IIO\n", __func__); - return PTR_ERR(iio); + return -ENOMEM; } adc = iio_priv(iio); -- cgit v1.2.3 From 4d885f2d3b778681f22ab7df9b4ccd104ffcd7f4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Jan 2018 17:05:23 +0100 Subject: sound: Remove unused register_sound_midi() and co These helpers are no longer used after the removal of the legacy OSS drivers. Let's clean up. Signed-off-by: Takashi Iwai --- include/linux/sound.h | 2 -- sound/sound_core.c | 35 ----------------------------------- 2 files changed, 37 deletions(-) diff --git a/include/linux/sound.h b/include/linux/sound.h index 3c6d393c7f29..ec85b7a1f8d1 100644 --- a/include/linux/sound.h +++ b/include/linux/sound.h @@ -12,11 +12,9 @@ struct device; extern int register_sound_special(const struct file_operations *fops, int unit); extern int register_sound_special_device(const struct file_operations *fops, int unit, struct device *dev); extern int register_sound_mixer(const struct file_operations *fops, int dev); -extern int register_sound_midi(const struct file_operations *fops, int dev); extern int register_sound_dsp(const struct file_operations *fops, int dev); extern void unregister_sound_special(int unit); extern void unregister_sound_mixer(int unit); -extern void unregister_sound_midi(int unit); extern void unregister_sound_dsp(int unit); #endif /* _LINUX_SOUND_H */ diff --git a/sound/sound_core.c b/sound/sound_core.c index 99b73c675743..8b026b66cf18 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -452,26 +452,6 @@ int register_sound_mixer(const struct file_operations *fops, int dev) EXPORT_SYMBOL(register_sound_mixer); -/** - * register_sound_midi - register a midi device - * @fops: File operations for the driver - * @dev: Unit number to allocate - * - * Allocate a midi device. Unit is the number of the midi device requested. - * Pass -1 to request the next free midi unit. - * - * Return: On success, the allocated number is returned. On failure, - * a negative error code is returned. - */ - -int register_sound_midi(const struct file_operations *fops, int dev) -{ - return sound_insert_unit(&chains[2], fops, dev, 2, 130, - "midi", S_IRUSR | S_IWUSR, NULL); -} - -EXPORT_SYMBOL(register_sound_midi); - /* * DSP's are registered as a triple. Register only one and cheat * in open - see below. @@ -532,21 +512,6 @@ void unregister_sound_mixer(int unit) EXPORT_SYMBOL(unregister_sound_mixer); -/** - * unregister_sound_midi - unregister a midi device - * @unit: unit number to allocate - * - * Release a sound device that was allocated with register_sound_midi(). - * The unit passed is the return value from the register function. - */ - -void unregister_sound_midi(int unit) -{ - sound_remove_unit(&chains[2], unit); -} - -EXPORT_SYMBOL(unregister_sound_midi); - /** * unregister_sound_dsp - unregister a DSP device * @unit: unit number to allocate -- cgit v1.2.3 From 8ac60e733f7c9c41e4c125619a2f8390aca9d4db Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Jan 2018 17:10:34 +0100 Subject: sound: Remove leftover msnd init declarations Some obsoleted functions are still declared in sound_core.c. Get rid of them. Signed-off-by: Takashi Iwai --- sound/sound_core.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sound/sound_core.c b/sound/sound_core.c index 8b026b66cf18..b4efb22db561 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -119,13 +119,6 @@ struct sound_unit char name[32]; }; -#ifdef CONFIG_SOUND_MSNDCLAS -extern int msnd_classic_init(void); -#endif -#ifdef CONFIG_SOUND_MSNDPIN -extern int msnd_pinnacle_init(void); -#endif - /* * By default, OSS sound_core claims full legacy minor range (0-255) * of SOUND_MAJOR to trap open attempts to any sound minor and -- cgit v1.2.3 From 5954c4a1455c3bc42acb2c286744eae1aaa00918 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 11 Jan 2018 14:05:11 -0600 Subject: ASoC: rt5645: add fallback case for jack detection support Commit 78f5605c0329 ("ASoC: rt5645: cleanup DMI matching code") did a lot of useful cleanups. This patch adds a default case to enable jack detection if there is no pdata, device property or quirk. The chosen jd-mode3 is the most common and should limit the addition of new DMI-based quirks. Existing DMI quirks which only set this mode are left as is and not removed. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index fbaf36aeb587..5292fca2f54f 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3739,6 +3739,17 @@ static const struct dmi_system_id dmi_platform_data[] = { { } }; +static bool rt5645_check_dp(struct device *dev) +{ + if (device_property_present(dev, "realtek,in2-differential") || + device_property_present(dev, "realtek,dmic1-data-pin") || + device_property_present(dev, "realtek,dmic2-data-pin") || + device_property_present(dev, "realtek,jd-mode")) + return true; + + return false; +} + static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev) { rt5645->pdata.in2_diff = device_property_read_bool(dev, @@ -3779,8 +3790,10 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, if (pdata) rt5645->pdata = *pdata; - else + else if (rt5645_check_dp(&i2c->dev)) rt5645_parse_dt(rt5645, &i2c->dev); + else + rt5645->pdata = jd_mode3_platform_data; if (quirk != -1) { rt5645->pdata.in2_diff = QUIRK_IN2_DIFF(quirk); -- cgit v1.2.3 From 3c22a73fb87366851dcf48d852357a6d808921cc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 11 Jan 2018 13:52:08 -0600 Subject: ASoC: Intel: bytcht_es8316: fix HID handling Same problem as with previous machine drivers, the codec dai uses a hard-coded name of "i2c-ESSX8316:00" but ACPI provides "i2c-ESSX8316:01" in some systems. Fix by overriding the hard-coded value with the codec name derived from the HID information Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=189261 Signed-off-by: Pierre-Louis Bossart Reviewed-by: Andy Shevchenko Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 1 + sound/soc/intel/boards/bytcht_es8316.c | 26 +++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index de598dcbef30..d4e103615f51 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -139,6 +139,7 @@ config SND_SOC_INTEL_BYT_CHT_DA7213_MACH config SND_SOC_INTEL_BYT_CHT_ES8316_MACH tristate "Baytrail & Cherrytrail with ES8316 codec" depends on X86_INTEL_LPSS && I2C && ACPI + select SND_SOC_ACPI select SND_SOC_ES8316 help This adds support for ASoC machine driver for Intel(R) Baytrail & diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 8088396717e3..ae24f6205f05 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -232,15 +232,39 @@ static struct snd_soc_card byt_cht_es8316_card = { .fully_routed = true, }; +static char codec_name[16]; /* i2c-:00 with HID being 8 chars */ + static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { - int ret = 0; struct byt_cht_es8316_private *priv; + struct snd_soc_acpi_mach *mach; + const char *i2c_name = NULL; + int dai_index = 0; + int i; + int ret = 0; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); if (!priv) return -ENOMEM; + mach = (&pdev->dev)->platform_data; + /* fix index of codec dai */ + for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) { + if (!strcmp(byt_cht_es8316_dais[i].codec_name, + "i2c-ESSX8316:00")) { + dai_index = i; + break; + } + } + + /* fixup codec name based on HID */ + i2c_name = snd_soc_acpi_find_name_from_hid(mach->id); + if (i2c_name) { + snprintf(codec_name, sizeof(codec_name), + "%s%s", "i2c-", i2c_name); + byt_cht_es8316_dais[dai_index].codec_name = codec_name; + } + /* register the soc card */ byt_cht_es8316_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); -- cgit v1.2.3 From 2be2d57986431626e905ee344086affa44c5bb9b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 11 Jan 2018 13:52:09 -0600 Subject: ASoC: acpi: remove hard-coded i2c-device name length Remove hard-codec [16] array size, replace with clearer description and dependency on ACPI_ID_LEN No functionality change Suggested-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart Reviewed-by: Andy Shevchenko Acked-By: Vinod Koul Signed-off-by: Mark Brown --- include/sound/soc-acpi.h | 3 +++ sound/soc/intel/boards/bytcht_da7213.c | 2 +- sound/soc/intel/boards/bytcht_es8316.c | 2 +- sound/soc/intel/boards/bytcr_rt5640.c | 2 +- sound/soc/intel/boards/bytcr_rt5651.c | 2 +- sound/soc/intel/boards/cht_bsw_rt5645.c | 4 ++-- sound/soc/intel/boards/cht_bsw_rt5672.c | 2 +- 7 files changed, 10 insertions(+), 7 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index d1aaf876cd26..83320af8def2 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -27,6 +27,9 @@ struct snd_soc_acpi_package_context { bool data_valid; }; +/* codec name is used in DAIs is i2c-:00 with HID being 8 chars */ +#define SND_ACPI_I2C_ID_LEN (4 + ACPI_ID_LEN + 3 + 1) + #if IS_ENABLED(CONFIG_ACPI) /* translation fron HID to I2C name, needed for DAI codec_name */ const char *snd_soc_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]); diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index c4d82ad41bd7..6219c04d4731 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -219,7 +219,7 @@ static struct snd_soc_card bytcht_da7213_card = { .num_dapm_routes = ARRAY_SIZE(audio_map), }; -static char codec_name[16]; /* i2c-:00 with HID being 8 chars */ +static char codec_name[SND_ACPI_I2C_ID_LEN]; static int bytcht_da7213_probe(struct platform_device *pdev) { diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index ae24f6205f05..079f35cd4eaf 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -232,7 +232,7 @@ static struct snd_soc_card byt_cht_es8316_card = { .fully_routed = true, }; -static char codec_name[16]; /* i2c-:00 with HID being 8 chars */ +static char codec_name[SND_ACPI_I2C_ID_LEN]; static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index f2c0fc415e52..4548f75498d0 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -713,7 +713,7 @@ static struct snd_soc_card byt_rt5640_card = { .fully_routed = true, }; -static char byt_rt5640_codec_name[16]; /* i2c-:00 with HID being 8 chars */ +static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 22c9cc5d135e..5a6b7dedb773 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -509,7 +509,7 @@ static struct snd_soc_card byt_rt5651_card = { .fully_routed = true, }; -static char byt_rt5651_codec_name[16]; /* i2c-:00 with HID being 8 chars */ +static char byt_rt5651_codec_name[SND_ACPI_I2C_ID_LEN]; static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) { diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 18d129caa974..cef6a8c31c8d 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -49,7 +49,7 @@ struct cht_acpi_card { struct cht_mc_private { struct snd_soc_jack jack; struct cht_acpi_card *acpi_card; - char codec_name[16]; + char codec_name[SND_ACPI_I2C_ID_LEN]; struct clk *mclk; }; @@ -499,7 +499,7 @@ static struct cht_acpi_card snd_soc_cards[] = { {"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650}, }; -static char cht_rt5645_codec_name[16]; /* i2c-:00 with HID being 8 chars */ +static char cht_rt5645_codec_name[SND_ACPI_I2C_ID_LEN]; static char cht_rt5645_codec_aif_name[12]; /* = "rt5645-aif[1|2]" */ static char cht_rt5645_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index f8f21eee9b2d..1f3d38dc4fcb 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -35,7 +35,7 @@ struct cht_mc_private { struct snd_soc_jack headset; - char codec_name[16]; + char codec_name[SND_ACPI_I2C_ID_LEN]; struct clk *mclk; }; -- cgit v1.2.3 From ef3d687c795c82c44aef1bf25fcd4900ba60be9a Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Thu, 11 Jan 2018 16:27:04 +0000 Subject: ASoC: cs42l73: Remove trailing semicolon The trailing semicolon is an empty statement that does no operation. Removing it since it doesn't do anything. Signed-off-by: Luis de Bethencourt Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l73.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index dde37e569ade..aebaa97490b6 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1355,7 +1355,7 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, ret = regmap_read(cs42l73->regmap, CS42L73_REVID, ®); if (ret < 0) { dev_err(&i2c_client->dev, "Get Revision ID failed\n"); - return ret;; + return ret; } dev_info(&i2c_client->dev, -- cgit v1.2.3 From 3a1479599a610cd49cbf91da68963ade90ee0fa3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 12 Jan 2018 23:16:17 +0200 Subject: ASoC: Intel - Convert to use acpi_dev_get_first_match_name() Instead of home grown snd_soc_acpi_find_name_from_hid() use acpi_dev_get_first_match_name(). Tested-by: Pierre-Louis Bossart Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- include/sound/soc-acpi.h | 7 ------- sound/soc/intel/boards/bytcht_da7213.c | 2 +- sound/soc/intel/boards/bytcht_es8316.c | 2 +- sound/soc/intel/boards/bytcr_rt5640.c | 2 +- sound/soc/intel/boards/bytcr_rt5651.c | 2 +- sound/soc/intel/boards/cht_bsw_rt5645.c | 2 +- sound/soc/intel/boards/cht_bsw_rt5672.c | 2 +- sound/soc/soc-acpi.c | 33 --------------------------------- 8 files changed, 6 insertions(+), 46 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 83320af8def2..082224275f52 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -31,16 +31,9 @@ struct snd_soc_acpi_package_context { #define SND_ACPI_I2C_ID_LEN (4 + ACPI_ID_LEN + 3 + 1) #if IS_ENABLED(CONFIG_ACPI) -/* translation fron HID to I2C name, needed for DAI codec_name */ -const char *snd_soc_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]); bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], struct snd_soc_acpi_package_context *ctx); #else -static inline const char * -snd_soc_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]) -{ - return NULL; -} static inline bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], struct snd_soc_acpi_package_context *ctx) diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index 6219c04d4731..2179dedb28ad 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -243,7 +243,7 @@ static int bytcht_da7213_probe(struct platform_device *pdev) } /* fixup codec name based on HID */ - i2c_name = snd_soc_acpi_find_name_from_hid(mach->id); + i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); if (i2c_name) { snprintf(codec_name, sizeof(codec_name), "%s%s", "i2c-", i2c_name); diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 079f35cd4eaf..305e7f4fe55a 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -258,7 +258,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) } /* fixup codec name based on HID */ - i2c_name = snd_soc_acpi_find_name_from_hid(mach->id); + i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); if (i2c_name) { snprintf(codec_name, sizeof(codec_name), "%s%s", "i2c-", i2c_name); diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 4548f75498d0..b6a1cfeec830 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -762,7 +762,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) } /* fixup codec name based on HID */ - i2c_name = snd_soc_acpi_find_name_from_hid(mach->id); + i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); if (i2c_name) { snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name), "%s%s", "i2c-", i2c_name); diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 5a6b7dedb773..456526a93dd5 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -539,7 +539,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) } /* fixup codec name based on HID */ - i2c_name = snd_soc_acpi_find_name_from_hid(mach->id); + i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); if (i2c_name) { snprintf(byt_rt5651_codec_name, sizeof(byt_rt5651_codec_name), "%s%s", "i2c-", i2c_name); diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index cef6a8c31c8d..976ea6bf9539 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -566,7 +566,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } /* fixup codec name based on HID */ - i2c_name = snd_soc_acpi_find_name_from_hid(mach->id); + i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); if (i2c_name) { snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name), "%s%s", "i2c-", i2c_name); diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 1f3d38dc4fcb..c14a52d2f714 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -396,7 +396,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) /* fixup codec name based on HID */ if (mach) { - i2c_name = snd_soc_acpi_find_name_from_hid(mach->id); + i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); if (i2c_name) { snprintf(drv->codec_name, sizeof(drv->codec_name), "i2c-%s", i2c_name); diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c index 7f43c9bf3d09..3d7e1ff79139 100644 --- a/sound/soc/soc-acpi.c +++ b/sound/soc/soc-acpi.c @@ -16,39 +16,6 @@ #include -static acpi_status snd_soc_acpi_find_name(acpi_handle handle, u32 level, - void *context, void **ret) -{ - struct acpi_device *adev; - const char *name = NULL; - - if (acpi_bus_get_device(handle, &adev)) - return AE_OK; - - if (adev->status.present && adev->status.functional) { - name = acpi_dev_name(adev); - *(const char **)ret = name; - return AE_CTRL_TERMINATE; - } - - return AE_OK; -} - -const char *snd_soc_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]) -{ - const char *name = NULL; - acpi_status status; - - status = acpi_get_devices(hid, snd_soc_acpi_find_name, NULL, - (void **)&name); - - if (ACPI_FAILURE(status) || name[0] == '\0') - return NULL; - - return name; -} -EXPORT_SYMBOL_GPL(snd_soc_acpi_find_name_from_hid); - struct snd_soc_acpi_mach * snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines) { -- cgit v1.2.3 From 949293d45d6b0951e2dfdfd670a9c0092b10fd27 Mon Sep 17 00:00:00 2001 From: Christian Fischer Date: Fri, 12 Jan 2018 14:22:59 +0100 Subject: ASoC: mxs-sgtl5000: add audio-routing support Add dapm_widgets to machine-driver (from imx-sgtl5000). If the "audio-routing"-property is present at probing the dapm-widgets getting linked to the card. Signed-off-by: Christian Fischer Signed-off-by: Mark Brown --- .../bindings/sound/mxs-audio-sgtl5000.txt | 33 +++++++++++++++++++--- sound/soc/mxs/mxs-sgtl5000.c | 20 +++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt index 601c518eddaa..4eb980bd0287 100644 --- a/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt +++ b/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt @@ -1,10 +1,31 @@ * Freescale MXS audio complex with SGTL5000 codec Required properties: -- compatible: "fsl,mxs-audio-sgtl5000" -- model: The user-visible name of this sound complex -- saif-controllers: The phandle list of the MXS SAIF controller -- audio-codec: The phandle of the SGTL5000 audio codec +- compatible : "fsl,mxs-audio-sgtl5000" +- model : The user-visible name of this sound complex +- saif-controllers : The phandle list of the MXS SAIF controller +- audio-codec : The phandle of the SGTL5000 audio codec +- audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names could be power supplies, SGTL5000 + pins, and the jacks on the board: + + Power supplies: + * Mic Bias + + SGTL5000 pins: + * MIC_IN + * LINE_IN + * HP_OUT + * LINE_OUT + + Board connectors: + * Mic Jack + * Line In Jack + * Headphone Jack + * Line Out Jack + * Ext Spk Example: @@ -14,4 +35,8 @@ sound { model = "imx28-evk-sgtl5000"; saif-controllers = <&saif0 &saif1>; audio-codec = <&sgtl5000>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; }; diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index 2ed3240cc682..b593f76212e0 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -93,6 +93,14 @@ static struct snd_soc_dai_link mxs_sgtl5000_dai[] = { }, }; +static const struct snd_soc_dapm_widget mxs_sgtl5000_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_LINE("Line In Jack", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_SPK("Line Out Jack", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), +}; + static struct snd_soc_card mxs_sgtl5000 = { .name = "mxs_sgtl5000", .owner = THIS_MODULE, @@ -141,6 +149,18 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev) card->dev = &pdev->dev; + if (of_find_property(np, "audio-routing", NULL)) { + card->dapm_widgets = mxs_sgtl5000_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(mxs_sgtl5000_dapm_widgets); + + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); + if (ret) { + dev_err(&pdev->dev, "failed to parse audio-routing (%d)\n", + ret); + return ret; + } + } + ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", -- cgit v1.2.3 From 33193dca671c8b75eb030234cefdcd2ceebd7516 Mon Sep 17 00:00:00 2001 From: Martin Peres Date: Sun, 14 Jan 2018 18:05:53 +0200 Subject: ALSA: usb-audio: Add a quirk for Nura's first gen headset The capture interface does not work, and the playback interface actually supports only 48kHz unlike what is advertised (44.1, 32, 22, 16, 8). The only unknown here is if there are other devices that use the same product ID, but given that this ID is currently unknown, I would assume it is specially allocated for the nura headset. Signed-off-by: Martin Peres Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 8a59d4782a0f..50252046b01d 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3277,4 +3277,52 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), } }, +{ + /* + * Nura's first gen headphones use Cambridge Silicon Radio's vendor + * ID, but it looks like the product ID actually is only for Nura. + * The capture interface does not work at all (even on Windows), + * and only the 48 kHz sample rate works for the playback interface. + */ + USB_DEVICE(0x0a12, 0x1243), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_MIXER, + }, + /* Capture */ + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE, + }, + /* Playback */ + { + .ifnum = 2, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .iface = 2, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_FILL_MAX | + UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x03, + .ep_attr = USB_ENDPOINT_XFER_ISOC, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .nr_rates = 1, + .rate_table = (unsigned int[]) { + 48000 + } + } + }, + } + } +}, + #undef USB_DEVICE_VENDOR_SPEC -- cgit v1.2.3 From 671ec859e5ee06ab0bf968e639a25576b18865ad Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 15 Jan 2018 16:48:36 +0100 Subject: ALSA: seq: Process queue tempo/ppq change in a shot The SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO ioctl sets the tempo and the ppq in a single call, while the current implementation updates each value one by one. This is a bit racy, and also suboptimal from the performance POV, as each call does re-acquire the lock and invokes the update of ALSA timer resolution. This patch reorganizes the code slightly so that we change both the tempo and the ppq in a shot. The skew value can be put into the same lock, but this is rather a rarely used feature and completely independent from the temp/ppq (it's evaluated only in the interrupt), so it's left as it was. Signed-off-by: Takashi Iwai --- sound/core/seq/seq_queue.c | 4 +--- sound/core/seq/seq_timer.c | 13 ++++++++----- sound/core/seq/seq_timer.h | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 79e0c5604ef8..0428e9061b47 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -497,9 +497,7 @@ int snd_seq_queue_timer_set_tempo(int queueid, int client, return -EPERM; } - result = snd_seq_timer_set_tempo(q->timer, info->tempo); - if (result >= 0) - result = snd_seq_timer_set_ppq(q->timer, info->ppq); + result = snd_seq_timer_set_tempo_ppq(q->timer, info->tempo, info->ppq); if (result >= 0 && info->skew_base > 0) result = snd_seq_timer_set_skew(q->timer, info->skew_value, info->skew_base); diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index b80985fbc334..23167578231f 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -191,14 +191,15 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo) return 0; } -/* set current ppq */ -int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq) +/* set current tempo and ppq in a shot */ +int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq) { + int changed; unsigned long flags; if (snd_BUG_ON(!tmr)) return -EINVAL; - if (ppq <= 0) + if (tempo <= 0 || ppq <= 0) return -EINVAL; spin_lock_irqsave(&tmr->lock, flags); if (tmr->running && (ppq != tmr->ppq)) { @@ -208,9 +209,11 @@ int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq) pr_debug("ALSA: seq: cannot change ppq of a running timer\n"); return -EBUSY; } - + changed = (tempo != tmr->tempo) || (ppq != tmr->ppq); + tmr->tempo = tempo; tmr->ppq = ppq; - snd_seq_timer_set_tick_resolution(tmr); + if (changed) + snd_seq_timer_set_tick_resolution(tmr); spin_unlock_irqrestore(&tmr->lock, flags); return 0; } diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h index 9506b661fe5b..62f390671096 100644 --- a/sound/core/seq/seq_timer.h +++ b/sound/core/seq/seq_timer.h @@ -131,7 +131,7 @@ int snd_seq_timer_stop(struct snd_seq_timer *tmr); int snd_seq_timer_start(struct snd_seq_timer *tmr); int snd_seq_timer_continue(struct snd_seq_timer *tmr); int snd_seq_timer_set_tempo(struct snd_seq_timer *tmr, int tempo); -int snd_seq_timer_set_ppq(struct snd_seq_timer *tmr, int ppq); +int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq); int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr, snd_seq_tick_time_t position); int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr, snd_seq_real_time_t position); int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, unsigned int base); -- cgit v1.2.3 From 123af9043e93cb6f235207d260d50f832cdb5439 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 15 Jan 2018 11:08:38 +0300 Subject: ASoC: au1x: Fix timeout tests in au1xac97c_ac97_read() The loop timeout doesn't work because it's a post op and ends with "tmo" set to -1. I changed it from a post-op to a pre-op and I changed the initial the starting value from 5 to 6 so we still iterate 5 times. I left the other as it was because it's a large number. Fixes: b3c70c9ea62a ("ASoC: Alchemy AC97C/I2SC audio support") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/au1x/ac97c.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c index 29a97d52e8ad..66d6c52e7761 100644 --- a/sound/soc/au1x/ac97c.c +++ b/sound/soc/au1x/ac97c.c @@ -91,8 +91,8 @@ static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97, do { mutex_lock(&ctx->lock); - tmo = 5; - while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--) + tmo = 6; + while ((RD(ctx, AC97_STATUS) & STAT_CP) && --tmo) udelay(21); /* wait an ac97 frame time */ if (!tmo) { pr_debug("ac97rd timeout #1\n"); @@ -105,7 +105,7 @@ static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97, * poll, Forrest, poll... */ tmo = 0x10000; - while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--) + while ((RD(ctx, AC97_STATUS) & STAT_CP) && --tmo) asm volatile ("nop"); data = RD(ctx, AC97_CMDRESP); -- cgit v1.2.3 From abaca806fd13afd069e04e883de8ec75924b0598 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 15 Jan 2018 09:57:39 +0100 Subject: IIO: ADC: stm32-dfsdm: code optimization Use of_device_get_match_data to optimize the source code. No check is needed on dev_data as match table is defined in driver. Signed-off-by: Arnaud Pouliquen Acked-by: Jonathan Cameron Signed-off-by: Mark Brown --- drivers/iio/adc/stm32-dfsdm-adc.c | 9 +-------- drivers/iio/adc/stm32-dfsdm-core.c | 8 +------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 5e871404f565..3fe9b34ac6af 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -1087,18 +1087,11 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; const struct stm32_dfsdm_dev_data *dev_data; struct iio_dev *iio; - const struct of_device_id *of_id; char *name; int ret, irq, val; - of_id = of_match_node(stm32_dfsdm_adc_match, np); - if (!of_id->data) { - dev_err(&pdev->dev, "Data associated to device is missing\n"); - return -EINVAL; - } - - dev_data = (const struct stm32_dfsdm_dev_data *)of_id->data; + dev_data = of_device_get_match_data(dev); iio = devm_iio_device_alloc(dev, sizeof(*adc)); if (!iio) { dev_err(dev, "%s: Failed to allocate IIO\n", __func__); diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index 6cd655f8239b..6290332cfd3f 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -242,7 +242,6 @@ MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match); static int stm32_dfsdm_probe(struct platform_device *pdev) { struct dfsdm_priv *priv; - const struct of_device_id *of_id; const struct stm32_dfsdm_dev_data *dev_data; struct stm32_dfsdm *dfsdm; int ret; @@ -253,13 +252,8 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) priv->pdev = pdev; - of_id = of_match_node(stm32_dfsdm_of_match, pdev->dev.of_node); - if (!of_id->data) { - dev_err(&pdev->dev, "Data associated to device is missing\n"); - return -EINVAL; - } + dev_data = of_device_get_match_data(&pdev->dev); - dev_data = (const struct stm32_dfsdm_dev_data *)of_id->data; dfsdm = &priv->dfsdm; dfsdm->fl_list = devm_kcalloc(&pdev->dev, dev_data->num_filters, sizeof(*dfsdm->fl_list), GFP_KERNEL); -- cgit v1.2.3 From 1175d0f9f4031ce02845f6f843f58a9caaee7817 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 15 Jan 2018 10:00:26 +0100 Subject: IIO: ADC: stm32-dfsdm: fix static check warning iio_priv does not return an error pointer, so check is not valid. Patch suppresses it. Signed-off-by: Arnaud Pouliquen Acked-by: Jonathan Cameron Signed-off-by: Mark Brown --- drivers/iio/adc/stm32-dfsdm-adc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 3fe9b34ac6af..daa026d6a94f 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -1099,10 +1099,6 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) } adc = iio_priv(iio); - if (IS_ERR(adc)) { - dev_err(dev, "%s: Failed to allocate ADC\n", __func__); - return PTR_ERR(adc); - } adc->dfsdm = dev_get_drvdata(dev->parent); iio->dev.parent = dev; -- cgit v1.2.3 From c469652bb5e8fb715db7d152f46d33b3740c9b87 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 15 Jan 2018 10:44:35 +0100 Subject: ALSA: hda - Use IS_REACHABLE() for dependency on input The commit ffcd28d88e4f ("ALSA: hda - Select INPUT for Realtek HD-audio codec") introduced the reverse-selection of CONFIG_INPUT for Realtek codec in order to avoid the mess with dependency between built-in and modules. Later on, we obtained IS_REACHABLE() macro exactly for this kind of problems, and now we can remove th INPUT selection in Kconfig and put IS_REACHABLE(INPUT) to the appropriate places in the code, so that the driver doesn't need to select other subsystem forcibly. Fixes: ffcd28d88e4f ("ALSA: hda - Select INPUT for Realtek HD-audio codec") Reported-by: Randy Dunlap Acked-by: Randy Dunlap # and build-tested Signed-off-by: Takashi Iwai --- sound/pci/hda/Kconfig | 1 - sound/pci/hda/patch_realtek.c | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 7f3b5ed81995..f7a492c382d9 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -88,7 +88,6 @@ config SND_HDA_PATCH_LOADER config SND_HDA_CODEC_REALTEK tristate "Build Realtek HD-audio codec support" select SND_HDA_GENERIC - select INPUT help Say Y or M here to include Realtek HD-audio codec support in snd-hda-intel driver, such as ALC880. diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 93d2ce891db6..552646c049fa 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3810,6 +3810,7 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec, } } +#if IS_REACHABLE(INPUT) static void gpio2_mic_hotkey_event(struct hda_codec *codec, struct hda_jack_callback *event) { @@ -3942,6 +3943,10 @@ static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec, spec->kb_dev = NULL; } } +#else /* INPUT */ +#define alc280_fixup_hp_gpio2_mic_hotkey NULL +#define alc233_fixup_lenovo_line2_mic_hotkey NULL +#endif /* INPUT */ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, const struct hda_fixup *fix, int action) -- cgit v1.2.3 From 3d3dd0d3ac207e8d28f6289896b99c1c0dad2fbe Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jan 2018 01:59:01 +0000 Subject: ASoC: tlv320dac33: fix regression by adding back .read/.write commit c4305af43a8 ("ASoC: use internal reg_cache on tlv320dac33") removed .read/.write from driver, but it might breaks non-regmap driver, because ALSA SoC framework might call it. To fix this regression, this patch back .read/.write Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 675f5b1b90a6..8c71d2f876ff 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -246,6 +246,19 @@ static int dac33_write(struct snd_soc_codec *codec, unsigned int reg, return ret; } +static int dac33_write_locked(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); + int ret; + + mutex_lock(&dac33->mutex); + ret = dac33_write(codec, reg, value); + mutex_unlock(&dac33->mutex); + + return ret; +} + #define DAC33_I2C_ADDR_AUTOINC 0x80 static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) @@ -1422,6 +1435,8 @@ static int dac33_soc_remove(struct snd_soc_codec *codec) } static const struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = { + .read = dac33_read_reg_cache, + .write = dac33_write_locked, .set_bias_level = dac33_set_bias_level, .idle_bias_off = true, -- cgit v1.2.3 From 7604d8068e6253c143b27ce7e164ee8e7a9da5b9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jan 2018 01:59:53 +0000 Subject: ASoC: uda1380: fix regression by adding back .read/.write commit c001bf633a9 ("ASoC: use internal reg_cache on uda1380") removed .read/.write from driver, but it might breaks non-regmap driver, because ALSA SoC framework might call it. To fix this regression, this patch back .read/.write Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/uda1380.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 46a495b4da8d..c73e6a192224 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -726,6 +726,8 @@ static int uda1380_probe(struct snd_soc_codec *codec) static const struct snd_soc_codec_driver soc_codec_dev_uda1380 = { .probe = uda1380_probe, + .read = uda1380_read_reg_cache, + .write = uda1380_write, .set_bias_level = uda1380_set_bias_level, .suspend_bias_off = true, -- cgit v1.2.3 From 3c89724e994f4aee6ae2637ccd4e12aa4f92666c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jan 2018 02:00:18 +0000 Subject: ASoC: cx20442: fix regression by adding back .read/.write commit 39b5a0f80c07f ("ASoC: cx20442: don't use reg_cache") removed .read/.write from driver, but it might breaks non-regmap driver, because ALSA SoC framework might call it. To fix this regression, this patch back .read/.write. and also this patch uses cx20442 internal reg_cache which is needed for .read/.write. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/cx20442.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 6b6f8e44369b..95bb10ba80dc 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -28,6 +28,7 @@ struct cx20442_priv { struct tty_struct *tty; struct regulator *por; + u8 reg_cache; }; #define CX20442_PM 0x0 @@ -88,6 +89,17 @@ static const struct snd_soc_dapm_route cx20442_audio_map[] = { {"ADC", NULL, "Input Mixer"}, }; +static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec); + + if (reg >= 1) + return -EINVAL; + + return cx20442->reg_cache; +} + enum v253_vls { V253_VLS_NONE = 0, V253_VLS_T, @@ -112,8 +124,6 @@ enum v253_vls { V253_VLS_TEST, }; -#if 0 -/* FIXME : these function will be re-used */ static int cx20442_pm_to_v253_vls(u8 value) { switch (value & ~(1 << CX20442_AGC)) { @@ -147,11 +157,10 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec); - u8 *reg_cache = codec->reg_cache; int vls, vsp, old, len; char buf[18]; - if (reg >= codec->driver->reg_cache_size) + if (reg >= 1) return -EINVAL; /* tty and write pointers required for talking to the modem @@ -159,8 +168,8 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg, if (!cx20442->tty || !cx20442->tty->ops->write) return -EIO; - old = reg_cache[reg]; - reg_cache[reg] = value; + old = cx20442->reg_cache; + cx20442->reg_cache = value; vls = cx20442_pm_to_v253_vls(value); if (vls < 0) @@ -190,7 +199,6 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg, return 0; } -#endif /* * Line discpline related code @@ -384,12 +392,12 @@ static int cx20442_codec_remove(struct snd_soc_codec *codec) return 0; } -static const u8 cx20442_reg; - static const struct snd_soc_codec_driver cx20442_codec_dev = { .probe = cx20442_codec_probe, .remove = cx20442_codec_remove, .set_bias_level = cx20442_set_bias_level, + .read = cx20442_read_reg_cache, + .write = cx20442_write, .component_driver = { .dapm_widgets = cx20442_dapm_widgets, -- cgit v1.2.3 From d0ff8ba57d9654e6f7a2e18f192bac3b93268fef Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jan 2018 02:00:59 +0000 Subject: ASoC: add Component level .read/.write In current ALSA SoC, Codec only has .read/.write callback. Codec will be merged into Component in next generation ALSA SoC, thus current Codec specific feature need to be merged into it. This is glue patch for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 3 +++ sound/soc/soc-io.c | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 1a7323238c49..6e865c2bcffe 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -802,6 +802,9 @@ struct snd_soc_component_driver { int (*suspend)(struct snd_soc_component *); int (*resume)(struct snd_soc_component *); + unsigned int (*read)(struct snd_soc_component *, unsigned int); + int (*write)(struct snd_soc_component *, unsigned int, unsigned int); + /* pcm creation and destruction */ int (*pcm_new)(struct snd_soc_pcm_runtime *); void (*pcm_free)(struct snd_pcm *); diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index 20340ade20a7..2bc1c4c17896 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -34,6 +34,10 @@ int snd_soc_component_read(struct snd_soc_component *component, ret = regmap_read(component->regmap, reg, val); else if (component->read) ret = component->read(component, reg, val); + else if (component->driver->read) { + *val = component->driver->read(component, reg); + ret = 0; + } else ret = -EIO; @@ -70,6 +74,8 @@ int snd_soc_component_write(struct snd_soc_component *component, return regmap_write(component->regmap, reg, val); else if (component->write) return component->write(component, reg, val); + else if (component->driver->write) + return component->driver->write(component, reg, val); else return -EIO; } -- cgit v1.2.3 From 3c7f69195cdd2a14ab85dfb32805e866eb241a6e Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Tue, 16 Jan 2018 13:26:26 +0000 Subject: ALSA: pcm: Fix trailing semicolon The trailing semicolon is an empty statement that does no operation. Removing it since it doesn't do anything. Signed-off-by: Luis de Bethencourt Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index f08772568c17..484a18d96371 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3446,7 +3446,7 @@ EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mmap); int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_struct *area) { - struct snd_pcm_runtime *runtime = substream->runtime;; + struct snd_pcm_runtime *runtime = substream->runtime; area->vm_page_prot = pgprot_noncached(area->vm_page_prot); return vm_iomap_memory(area, runtime->dma_addr, runtime->dma_bytes); -- cgit v1.2.3 From c2b691ee35004ba3d5428cf48672cbbf1a50fbfb Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Wed, 17 Jan 2018 15:22:55 +0800 Subject: ALSA: hda/realtek - Support headset mode for ALC215/ALC285/ALC289 This patch will enable headset mode for ALC215/ALC285/ALC289 platform. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 552646c049fa..2efba4bd9f2b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4086,8 +4086,11 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) case 0x10ec0668: alc_process_coef_fw(codec, coef0668); break; + case 0x10ec0215: case 0x10ec0225: + case 0x10ec0285: case 0x10ec0295: + case 0x10ec0289: case 0x10ec0299: alc_process_coef_fw(codec, coef0225); break; @@ -4209,8 +4212,11 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, alc_process_coef_fw(codec, coef0688); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; + case 0x10ec0215: case 0x10ec0225: + case 0x10ec0285: case 0x10ec0295: + case 0x10ec0289: case 0x10ec0299: alc_process_coef_fw(codec, alc225_pre_hsmode); alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10); @@ -4281,8 +4287,11 @@ static void alc_headset_mode_default(struct hda_codec *codec) }; switch (codec->core.vendor_id) { + case 0x10ec0215: case 0x10ec0225: + case 0x10ec0285: case 0x10ec0295: + case 0x10ec0289: case 0x10ec0299: alc_process_coef_fw(codec, alc225_pre_hsmode); alc_process_coef_fw(codec, coef0225); @@ -4424,8 +4433,11 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) case 0x10ec0668: alc_process_coef_fw(codec, coef0688); break; + case 0x10ec0215: case 0x10ec0225: + case 0x10ec0285: case 0x10ec0295: + case 0x10ec0289: case 0x10ec0299: val = alc_read_coef_idx(codec, 0x45); if (val & (1 << 9)) @@ -4528,8 +4540,11 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) case 0x10ec0668: alc_process_coef_fw(codec, coef0688); break; + case 0x10ec0215: case 0x10ec0225: + case 0x10ec0285: case 0x10ec0295: + case 0x10ec0289: case 0x10ec0299: alc_process_coef_fw(codec, coef0225); break; @@ -4658,8 +4673,11 @@ static void alc_determine_headset_type(struct hda_codec *codec) val = alc_read_coef_idx(codec, 0xbe); is_ctia = (val & 0x1c02) == 0x1c02; break; + case 0x10ec0215: case 0x10ec0225: + case 0x10ec0285: case 0x10ec0295: + case 0x10ec0289: case 0x10ec0299: snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); -- cgit v1.2.3 From 1b6832be1b61f63ef367e48050617e870a46b417 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Wed, 17 Jan 2018 15:32:03 +0800 Subject: ALSA: hda/realtek - update ALC215 depop optimize Add ALC215 its own depop functions for alc_init and alc_shutup. Assign it to ALC225 usage. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2efba4bd9f2b..0004e282a837 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7042,6 +7042,8 @@ static int patch_alc269(struct hda_codec *codec) case 0x10ec0285: case 0x10ec0289: spec->codec_variant = ALC269_TYPE_ALC215; + spec->shutup = alc225_shutup; + spec->init_hook = alc225_init; spec->gen.mixer_nid = 0; break; case 0x10ec0225: -- cgit v1.2.3 From fb2fcaeaad504ae9dad26f7b26a8ea840d00535f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 17 Jan 2018 10:17:08 +0000 Subject: ASoC: Intel: remove second duplicated assignment to pointer 'res' The second assignment to res is identical to the previous assignment so it is redundant and can be removed. Cleans up clang warning: sound/soc/intel/skylake/skl-topology.c:191:25: warning: Value stored to 'res' during its initialization is never read Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 28bc16a8e09a..73af6e19ebbd 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -190,7 +190,6 @@ skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig) u8 res_idx = mconfig->res_idx; struct skl_module_res *res = &mconfig->module->resources[res_idx]; - res = &mconfig->module->resources[res_idx]; skl->resource.mcps -= res->cps; } -- cgit v1.2.3 From 388fdb8f882af67ff8394d9420c1e0e42ba35619 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 16 Jan 2018 15:34:50 -0800 Subject: ALSA: usb-audio: Support changing input on Sound Blaster E1 The E1 has two headphone jacks, one of which can be set as a microphone input. In the default mode, it uses the built-in microphone as an input. By sending a special command, the second headphone jack is instead used as an input. This might work with the E3 as well, but I don't have one of those to test it. Signed-off-by: Ian Douglas Scott Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index e1e7ce9ab217..e6359d341878 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -27,6 +27,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include #include @@ -1721,6 +1722,83 @@ static int snd_microii_controls_create(struct usb_mixer_interface *mixer) return 0; } +/* Creative Sound Blaster E1 */ + +static int snd_soundblaster_e1_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = kcontrol->private_value; + return 0; +} + +static int snd_soundblaster_e1_switch_update(struct usb_mixer_interface *mixer, + unsigned char state) +{ + struct snd_usb_audio *chip = mixer->chip; + int err; + unsigned char buff[2]; + + buff[0] = 0x02; + buff[1] = state ? 0x02 : 0x00; + + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + err = snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), HID_REQ_SET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + 0x0202, 3, buff, 2); + snd_usb_unlock_shutdown(chip); + return err; +} + +static int snd_soundblaster_e1_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + unsigned char value = !!ucontrol->value.integer.value[0]; + int err; + + if (kcontrol->private_value == value) + return 0; + kcontrol->private_value = value; + err = snd_soundblaster_e1_switch_update(list->mixer, value); + return err < 0 ? err : 1; +} + +static int snd_soundblaster_e1_switch_resume(struct usb_mixer_elem_list *list) +{ + return snd_soundblaster_e1_switch_update(list->mixer, + list->kctl->private_value); +} + +static int snd_soundblaster_e1_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char *const texts[2] = { + "Mic", "Aux" + }; + + return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); +} + +static struct snd_kcontrol_new snd_soundblaster_e1_input_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", + .info = snd_soundblaster_e1_switch_info, + .get = snd_soundblaster_e1_switch_get, + .put = snd_soundblaster_e1_switch_put, + .private_value = 0, +}; + +static int snd_soundblaster_e1_switch_create(struct usb_mixer_interface *mixer) +{ + return add_single_ctl_with_resume(mixer, 0, + snd_soundblaster_e1_switch_resume, + &snd_soundblaster_e1_input_switch, + NULL); +} + int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) { int err = 0; @@ -1802,6 +1880,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x1235, 0x800c): /* Focusrite Scarlett 18i20 */ err = snd_scarlett_controls_create(mixer); break; + + case USB_ID(0x041e, 0x323b): /* Creative Sound Blaster E1 */ + err = snd_soundblaster_e1_switch_create(mixer); + break; } return err; -- cgit v1.2.3 From e29a22a86a20ea7651ff8c731ab034c31bd9764e Mon Sep 17 00:00:00 2001 From: Corentin LABBE Date: Wed, 17 Jan 2018 19:43:24 +0100 Subject: ASoC: Intel: remove select on non-existing SND_SOC_INTEL_COMMON SND_SST_ATOM_HIFI2_PLATFORM_PCI select SND_SOC_INTEL_COMMON which do not exists anymore. So remove this select. Fixes: c6059879be29 ("ASoC: Intel: Fix Kconfig with top-level selector") Signed-off-by: Corentin Labbe Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index b0bd1938b71e..f2c9e8c5970a 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -77,7 +77,6 @@ config SND_SST_ATOM_HIFI2_PLATFORM_PCI depends on X86 && PCI select SND_SST_IPC_PCI select SND_SOC_COMPRESS - select SND_SOC_INTEL_COMMON help If you have a Intel Medfield or Merrifield/Edison platform, then enable this option by saying Y or m. Distros will typically not -- cgit v1.2.3 From 8af5748fa48698a433ba9a1766204bda283dffa8 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 17 Jan 2018 13:48:54 -0200 Subject: ASoC: sgtl5000: Do not print error on probe deferral When the MCLK is not yet available when the codec is probed, probe deferral will happen and in this case we should not print an error message. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index f2bb4feba3b6..633cdcfc933d 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1332,10 +1332,13 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, sgtl5000->mclk = devm_clk_get(&client->dev, NULL); if (IS_ERR(sgtl5000->mclk)) { ret = PTR_ERR(sgtl5000->mclk); - dev_err(&client->dev, "Failed to get mclock: %d\n", ret); /* Defer the probe to see if the clk will be provided later */ if (ret == -ENOENT) ret = -EPROBE_DEFER; + + if (ret != -EPROBE_DEFER) + dev_err(&client->dev, "Failed to get mclock: %d\n", + ret); goto disable_regs; } -- cgit v1.2.3 From d04c413f2ab3aa5998bf86f7a2f6235ed82b2ee2 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 17 Jan 2018 13:48:55 -0200 Subject: ASoC: mxs-sgtl5000: Do not print error on probe deferral Probe deferral may happen, so do not print an error message in this case. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/mxs/mxs-sgtl5000.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index 2ed3240cc682..5a871f25f438 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -143,8 +143,9 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); return ret; } -- cgit v1.2.3 From 8d5737a5f53902a916ee1e1cb248c9b8b883b2ea Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Wed, 17 Jan 2018 13:50:50 +0100 Subject: ASoC: bcm2835: fix hw_params error when device is in prepared state If bcm2835 is configured as bitclock master calling hw_params() after prepare() fails with EBUSY. This also makes it impossible to use bcm2835 in full duplex mode. The error is caused by the split clock setup: clk_set_rate is called in hw_params, clk_prepare_enable in prepare. As hw_params doesn't check if the clock was already enabled clk_set_rate fails with EBUSY. Fix this by moving clock startup from prepare to hw_params and let hw_params properly deal with an already set up or enabled clock. Signed-off-by: Matthias Reichl Signed-off-by: Mark Brown --- sound/soc/bcm/bcm2835-i2s.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 2e449d7173fc..d5f73a8ab893 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -130,6 +130,7 @@ struct bcm2835_i2s_dev { struct regmap *i2s_regmap; struct clk *clk; bool clk_prepared; + int clk_rate; }; static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev) @@ -419,10 +420,19 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, } /* Clock should only be set up here if CPU is clock master */ - if (bit_clock_master) { - ret = clk_set_rate(dev->clk, bclk_rate); - if (ret) - return ret; + if (bit_clock_master && + (!dev->clk_prepared || dev->clk_rate != bclk_rate)) { + if (dev->clk_prepared) + bcm2835_i2s_stop_clock(dev); + + if (dev->clk_rate != bclk_rate) { + ret = clk_set_rate(dev->clk, bclk_rate); + if (ret) + return ret; + dev->clk_rate = bclk_rate; + } + + bcm2835_i2s_start_clock(dev); } /* Setup the frame format */ @@ -618,8 +628,6 @@ static int bcm2835_i2s_prepare(struct snd_pcm_substream *substream, struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); uint32_t cs_reg; - bcm2835_i2s_start_clock(dev); - /* * Clear both FIFOs if the one that should be started * is not empty at the moment. This should only happen -- cgit v1.2.3 From 166a5a33d5a7bfa62c039eb10e69589b09fd0557 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 18 Jan 2018 12:17:47 +0100 Subject: IIO: ADC: stm32-dfsdm: remove unused variable again The merge between commit abaca806fd13 ("IIO: ADC: stm32-dfsdm: code optimization") and commit 2353758bc2d4 ("IIO: ADC: stm32-dfsdm: avoid unused-variable warning") left one variable behind that is no longer needed and can be removed, as shown by the gcc warning: drivers/iio/adc/stm32-dfsdm-core.c: In function 'stm32_dfsdm_probe': drivers/iio/adc/stm32-dfsdm-core.c:245:29: error: unused variable 'of_id' [-Werror=unused-variable] Fixes: d84b4c7c706f ("Merge branch 'topic/iio' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-st-dfsdm") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- drivers/iio/adc/stm32-dfsdm-core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index 84277bcc465f..6290332cfd3f 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -242,7 +242,6 @@ MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match); static int stm32_dfsdm_probe(struct platform_device *pdev) { struct dfsdm_priv *priv; - const struct of_device_id *of_id; const struct stm32_dfsdm_dev_data *dev_data; struct stm32_dfsdm *dfsdm; int ret; -- cgit v1.2.3 From 031734b7d6532633d0cde73475c30646bf37cd6d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 Jan 2018 01:13:54 +0000 Subject: ASoC: soc-core: add missing EXPORT_SYMBOL_GPL() for snd_soc_rtdcom_lookup Reported-by: Atsushi Nemoto Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b9ca939fd05c..9b79c2199781 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -598,6 +598,7 @@ struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, return NULL; } +EXPORT_SYMBOL_GPL(snd_soc_rtdcom_lookup); struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, const char *dai_link, int stream) -- cgit v1.2.3 From 700c17ca8968f473631594e8a7c2cc880ba2c891 Mon Sep 17 00:00:00 2001 From: Donglin Peng Date: Thu, 18 Jan 2018 13:31:26 +0800 Subject: ASoC: use seq_file to dump the contents of dai_list,platform_list and codec_list Now the debugfs files dais/platforms/codecs have a size limit PAGE_SIZE and the user can not see the whole contents of dai_list/platform_list/codec_list when they are larger than this limit. This patch uses seq_file instead to make sure dais/platforms/codecs show the full contents of dai_list/platform_list/codec_list. Signed-off-by: Donglin Peng Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 111 +++++++++++++++++---------------------------------- 1 file changed, 37 insertions(+), 74 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c0edac80df34..7b582112e3fc 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -349,120 +349,84 @@ static void soc_init_codec_debugfs(struct snd_soc_component *component) "ASoC: Failed to create codec register debugfs file\n"); } -static ssize_t codec_list_read_file(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static int codec_list_seq_show(struct seq_file *m, void *v) { - char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - ssize_t len, ret = 0; struct snd_soc_codec *codec; - if (!buf) - return -ENOMEM; - mutex_lock(&client_mutex); - list_for_each_entry(codec, &codec_list, list) { - len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", - codec->component.name); - if (len >= 0) - ret += len; - if (ret > PAGE_SIZE) { - ret = PAGE_SIZE; - break; - } - } + list_for_each_entry(codec, &codec_list, list) + seq_printf(m, "%s\n", codec->component.name); mutex_unlock(&client_mutex); - if (ret >= 0) - ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); - - kfree(buf); + return 0; +} - return ret; +static int codec_list_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, codec_list_seq_show, NULL); } static const struct file_operations codec_list_fops = { - .read = codec_list_read_file, - .llseek = default_llseek,/* read accesses f_pos */ + .open = codec_list_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; -static ssize_t dai_list_read_file(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static int dai_list_seq_show(struct seq_file *m, void *v) { - char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - ssize_t len, ret = 0; struct snd_soc_component *component; struct snd_soc_dai *dai; - if (!buf) - return -ENOMEM; - mutex_lock(&client_mutex); - list_for_each_entry(component, &component_list, list) { - list_for_each_entry(dai, &component->dai_list, list) { - len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", - dai->name); - if (len >= 0) - ret += len; - if (ret > PAGE_SIZE) { - ret = PAGE_SIZE; - break; - } - } - } + list_for_each_entry(component, &component_list, list) + list_for_each_entry(dai, &component->dai_list, list) + seq_printf(m, "%s\n", dai->name); mutex_unlock(&client_mutex); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); - - kfree(buf); + return 0; +} - return ret; +static int dai_list_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, dai_list_seq_show, NULL); } static const struct file_operations dai_list_fops = { - .read = dai_list_read_file, - .llseek = default_llseek,/* read accesses f_pos */ + .open = dai_list_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; -static ssize_t platform_list_read_file(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) +static int platform_list_seq_show(struct seq_file *m, void *v) { - char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - ssize_t len, ret = 0; struct snd_soc_platform *platform; - if (!buf) - return -ENOMEM; - mutex_lock(&client_mutex); - list_for_each_entry(platform, &platform_list, list) { - len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", - platform->component.name); - if (len >= 0) - ret += len; - if (ret > PAGE_SIZE) { - ret = PAGE_SIZE; - break; - } - } + list_for_each_entry(platform, &platform_list, list) + seq_printf(m, "%s\n", platform->component.name); mutex_unlock(&client_mutex); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); - - kfree(buf); + return 0; +} - return ret; +static int platform_list_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, platform_list_seq_show, NULL); } static const struct file_operations platform_list_fops = { - .read = platform_list_read_file, - .llseek = default_llseek,/* read accesses f_pos */ + .open = platform_list_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; static void soc_init_card_debugfs(struct snd_soc_card *card) @@ -491,7 +455,6 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card) debugfs_remove_recursive(card->debugfs_card_root); } - static void snd_soc_debugfs_init(void) { snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL); -- cgit v1.2.3 From 1c9609e3a8cf5997bd35205cfda1ff2218ee793b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Jan 2018 14:18:34 +0100 Subject: ALSA: hda - Reduce the suspend time consumption for ALC256 ALC256 has its own quirk to override the shutup call, and it contains the COEF update for pulling down the headset jack control. Currently, the COEF update is called after clearing the headphone pin, and this seems triggering a stall of the codec communication, and results in a long delay over a second at suspend. A quick resolution is to swap the calls: at first with the COEF update, then clear the headphone pin. Fixes: 4a219ef8f370 ("ALSA: hda/realtek - Add ALC256 HP depop function") Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=198503 Reported-by: Paul Menzel Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0004e282a837..23475888192b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3154,11 +3154,13 @@ static void alc256_shutup(struct hda_codec *codec) if (hp_pin_sense) msleep(85); + /* 3k pull low control for Headset jack. */ + /* NOTE: call this before clearing the pin, otherwise codec stalls */ + alc_update_coef_idx(codec, 0x46, 0, 3 << 12); + snd_hda_codec_write(codec, hp_pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); - alc_update_coef_idx(codec, 0x46, 0, 3 << 12); /* 3k pull low control for Headset jack. */ - if (hp_pin_sense) msleep(100); -- cgit v1.2.3